DAY 12
浙大疏锦行一、整体逻辑思路分步拆解整个程序围绕“利用贝叶斯优化自动搜索 SVM 最佳超参数”这一目标展开分为三个层次1. 数据准备与预处理加载数据从指定路径读取 CSV 文件信用违约数据集。特征工程对分类变量如Home Ownership、Years in current job进行标签编码映射为数字。对Purpose进行独热编码One-Hot Encoding生成多个二值特征。对Term进行 0/1 映射Short Term → 0Long Term → 1。缺失值处理对所有数值型特征用众数填补缺失值fillna(mode)。但为了保险后续在 Pipeline 中再次用SimpleImputer确保无遗漏。划分数据集按 8:2 分割训练集和测试集测试集最终用于评估但本次优化仅使用训练集进行交叉验证。2. 贝叶斯优化核心流程定义目标函数svm_eval(C, gamma)构建一个PipelineSimpleImputer填补→StandardScaler标准化→SVCRBF 核。在训练集上进行5 折交叉验证返回平均准确率作为模型性能指标。设定搜索空间C正则化强度0.1 ~ 100gammaRBF 核参数0.001 ~ 1创建贝叶斯优化器BayesianOptimization初始随机探索init_points10次用于建立高斯过程先验。随后进行n_iter30次贝叶斯迭代利用概率代理模型指导后续采样。记录与计时记录每次迭代的参数和得分计算总耗时。3. 结果可视化与分析左图收敛曲线蓝色点线每次迭代的交叉验证准确率。红色虚线累计最优值历史最佳反映优化进程。绿色水平线最终找到的最优准确率。右图探索 vs 利用蓝色点前 10 次随机探索的结果。绿色点后 30 次贝叶斯优化的结果。红色竖线划分探索与利用阶段的分界线。统计输出最低/最高/平均得分、标准差、提升幅度以及最优参数组合。二、核心知识点总结1. 数据预处理与特征工程知识点本代码应用标签编码将有序/无序分类变量转换为整数如Own Home→ 1独热编码将Purpose扩展为多个 0/1 特征避免模型误认为类别间有大小关系众数填补用出现频率最高的值填充缺失数据适用于分类或离散特征标准化StandardScaler使特征均值为 0、方差为 1SVM 对尺度敏感这是必须的预处理2. SVM支持向量机核心思想目标找到一个超平面使两类样本之间的几何间隔最大化。核技巧通过kernelrbf高斯径向基核将数据映射到高维空间解决非线性分类问题。关键参数C惩罚系数控制对误分类样本的容忍度。C越大模型越偏向于拟合训练集可能过拟合C越小更注重间隔宽度可能欠拟合。gammaRBF 核的带宽决定单个样本的影响力范围。gamma越大决策边界越复杂容易过拟合gamma越小决策边界更平滑偏向欠拟合。SVM 的优缺点在小样本、高维数据上表现优异但对缺失值敏感本代码用SimpleImputer解决且计算复杂度随样本量增加而显著上升。3. 贝叶斯优化Bayesian Optimization与网格搜索/随机搜索的区别网格搜索穷举所有组合成本极高。随机搜索随机采样无方向性。贝叶斯优化基于高斯过程建立目标函数的概率模型代理模型通过采集函数如 UCB、EI在“探索”探索不确定区域和“利用”开发已知最优区域之间平衡高效找到最优参数。实现库bayesian-optimization它要求目标函数最大化某个指标我们最大化准确率。两个阶段随机探索init_points用少量随机采样初始化代理模型。贝叶斯迭代n_iter利用代理模型指导后续采样逐步逼近全局最优。4. Python 基础语法强化语法特性代码示例元组tuple不可变有序容器用作函数多返回值、字典键等字典 items() 方法返回(key, value)视图可用于迭代解包enumerate()遍历可迭代对象时同时获取索引和元素解包Unpackingfor param, (low, high) in pbounds.items()一次解包两层结构Pipeline将多个预处理步骤和模型串联保证交叉验证时数据不泄露try/except未显式使用但可加入可增强鲁棒性5. 可视化与结果解读收敛曲线若累计最优曲线快速上升并趋于平稳说明优化过程有效收敛。探索 vs 利用观察贝叶斯阶段是否比随机探索阶段获得更高准确率体现贝叶斯优化的“智能”之处。统计指标标准差可反映结果的稳定性提升幅度说明优化带来的增益。三、SVM 模型思想深度解读作业专用我选择的模型SVM支持向量机核心思想SVM 寻找一个最优超平面使得不同类别样本之间的间隔Margin最大化。对于线性不可分数据通过核函数将原始特征映射到高维空间在高维空间中寻找线性分隔超平面。与随机森林的对比随机森林是集成学习Bagging通过多棵树投票降低方差SVM 是几何模型基于结构风险最小化更注重分类边界的稳定性。为何选择 SVM 进行贝叶斯优化SVM 的性能强烈依赖C和gamma且两者相互制约传统网格搜索成本高贝叶斯优化能高效找到二者的平衡点。从可视化中得到的启示左图显示经过约 15 次迭代后累计最优值已接近最终最优说明贝叶斯优化能快速锁定优质参数区域大幅减少调参时间。四、代码中容易被忽略的关键细节Pipeline 中的SimpleImputer即便数据预处理已做填补在交叉验证中仍使用SimpleImputer确保每一折的训练集和验证集均无缺失值且填补参数仅从训练集学习避免数据泄露。标准化必须在交叉验证内部进行如果先对整个数据集标准化再划分会引入未来信息。本代码通过 Pipeline 保证每一折都独立标准化。参数空间的选择C和gamma通常使用对数尺度如 0.01~100但为了演示线性范围也能看到效果。实际应用中建议使用(0.01, 100)并用log-uniform采样本例未做但可以修改。迭代次数调整为了兼顾运行速度本例仅用 40 次迭代1030若电脑性能允许可增大至 100 次以获得更优结果。五、运行结果分析以你成功运行为例观察左图若累计最优曲线呈现“阶梯上升”状说明优化器在不断发现更好的参数。观察右图绿色点贝叶斯阶段普遍高于蓝色点随机探索证明贝叶斯优化确实在“利用”历史信息进行智能采样。输出统计信息中的“得分提升” 最高得分 - 第一次迭代得分反映优化效益。最终打印的最优参数组合可用于后续在测试集上评估模型泛化能力该步骤未在代码中实现可自行添加。六、延伸思考与课程笔记呼应你的笔记中提到“决策树是预测模型但优化问题与预测问题的边界越来越模糊”。本例正是通过优化超参数来提升预测性能将调参本身转化成一个优化问题体现了这种趋势。同时贝叶斯优化不仅可用于 SVM也可用于深度学习、强化学习等场景是一种通用的自动化调参工具。完整代码如下DAY12 贝叶斯优化可视化 —— SVM 版本完整可运行作者疏锦行按作业要求将模型改为 SVM数据路径C:\Python Study\Python60DaysChallenge-main\data.csv 一、元组类型保留教学 old_tuple (“张三”, 25, 92.5)print(f原始元组: {old_tuple}“)print(f原始类型: {type(old_tuple)}”)temp_list list(old_tuple)temp_list[1] 26new_tuple tuple(temp_list)print(f新元组: {new_tuple}\n) 二、字典的items方法保留教学 pbounds_demo {‘n_estimators’: (10, 3000), ‘max_depth’: (3, 500)}for param, (low, high) in pbounds_demo.items():print(f参数: {param} , 搜索范围: [{low}, {high}])my_dict {‘A’: 10, ‘B’: 20}for index, (key, value) in enumerate(my_dict.items()):print(f索引: {index}, 键: {key}, 值: {value}“)print(”\n “”*60 “\n”) 三、贝叶斯优化SVM import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport warningswarnings.filterwarnings(‘ignore’)设置中文字体plt.rcParams[‘font.sans-serif’] [‘SimHei’]plt.rcParams[‘axes.unicode_minus’] False----- 读取数据修改为你的真实路径-----file_path rC:\Python Study\Python60DaysChallenge-main\data.csvdata pd.read_csv(file_path)print(f数据形状: {data.shape})print(data.head()) 数据预处理完全复制你的原始流程Home Ownership 标签编码home_ownership_mapping {‘Own Home’: 1,‘Rent’: 2,‘Have Mortgage’: 3,‘Home Mortgage’: 4}data[‘Home Ownership’] data[‘Home Ownership’].map(home_ownership_mapping)Years in current job 标签编码years_in_job_mapping {‘ 1 year’: 1, ‘1 year’: 2, ‘2 years’: 3, ‘3 years’: 4, ‘4 years’: 5,‘5 years’: 6, ‘6 years’: 7, ‘7 years’: 8, ‘8 years’: 9, ‘9 years’: 10, ‘10 years’: 11}data[‘Years in current job’] data[‘Years in current job’].map(years_in_job_mapping)Purpose 独热编码data pd.get_dummies(data, columns[‘Purpose’])处理新增的独热编码列转为intdata2 pd.read_csv(file_path) # 重新读原始数据用于列差集list_final [i for i in data.columns if i not in data2.columns]for i in list_final:data[i] data[i].astype(int)Term 映射term_mapping {‘Short Term’: 0, ‘Long Term’: 1}data[‘Term’] data[‘Term’].map(term_mapping)data.rename(columns{‘Term’: ‘Long Term’}, inplaceTrue)连续特征用众数补全但可能仍有残留NaN后续在Pipeline中再次确保continuous_features data.select_dtypes(include[‘int64’, ‘float64’]).columns.tolist()for feature in continuous_features:mode_value data[feature].mode()[0]data[feature].fillna(mode_value, inplaceTrue)print(“✅ 数据预处理完成”)print(f最终特征数量: {data.shape[1]})划分训练集和测试集from sklearn.model_selection import train_test_splitX data.drop([‘Credit Default’], axis1)y data[‘Credit Default’]X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42)print(f训练集大小: {X_train.shape}“)print(f测试集大小: {X_test.shape}”) 引入 SVM 及必要的预处理加入缺失值填补 from sklearn.svm import SVCfrom sklearn.preprocessing import StandardScalerfrom sklearn.pipeline import Pipelinefrom sklearn.impute import SimpleImputerfrom sklearn.model_selection import cross_val_scorefrom bayes_opt import BayesianOptimizationimport time定义目标函数使用 Pipeline 包含填补、标准化、SVMdef svm_eval(C, gamma):“”SVM 目标函数最大化交叉验证准确率C: 正则化参数惩罚系数gamma: RBF核的带宽参数“”# 创建包含填补、标准化和SVM的Pipelinepipeline Pipeline([(‘imputer’, SimpleImputer(strategy‘most_frequent’)), # 众数填补缺失值(‘scaler’, StandardScaler()),(‘svm’, SVC(kernel‘rbf’, CC, gammagamma, random_state42))])# 5折交叉验证scores cross_val_score(pipeline, X_train, y_train, cv5, scoring‘accuracy’)return np.mean(scores)定义SVM超参数搜索空间常用范围pbounds {‘C’: (0.1, 100), # 对数尺度常用但为了演示用线性范围‘gamma’: (0.001, 1) # 同样线性范围}print(“\nSVM 参数搜索范围:”)for param, (low, high) in pbounds.items():print(f {param}: [{low}, {high}])创建贝叶斯优化器optimizer BayesianOptimization(fsvm_eval,pboundspbounds,random_state42,verbose2)start_time time.time()运行优化迭代次数可调此处使用 10次随机探索 30次贝叶斯优化optimizer.maximize(init_points10,n_iter30)end_time time.time()print(f优化完成总耗时: {end_time - start_time:.2f} 秒.center(80)) 可视化iterations []scores []for i, res in enumerate(optimizer.res):iterations.append(i 1)scores.append(res[‘target’])best_scores []current_best -np.inffor score in scores:if score current_best:current_best scorebest_scores.append(current_best)fig, (ax1, ax2) plt.subplots(1, 2, figsize(16, 5))左图ax1.plot(iterations, scores, ‘o-’, label‘每次迭代得分’, alpha0.7, markersize6)ax1.plot(iterations, best_scores, ‘r–’, label‘累计最优得分’, linewidth2)ax1.axhline(yoptimizer.max[‘target’], color‘green’, linestyle‘:’,labelf’最终最优: {optimizer.max[“target”]:.4f})ax1.set_xlabel(‘迭代次数’, fontsize12)ax1.set_ylabel(‘准确率’, fontsize12)ax1.set_title(‘SVM 贝叶斯优化收敛曲线’, fontsize14, fontweight‘bold’)ax1.legend()ax1.grid(True, alpha0.3)右图随机探索 vs 贝叶斯优化init_points 10 # 与上方的 init_points 保持一致ax2.plot(iterations[:init_points], scores[:init_points], ‘bo-’,labelf’随机探索 (前{init_points}次)‘, markersize8, alpha0.7)ax2.plot(iterations[init_points:], scores[init_points:], ‘go-’,labelf’贝叶斯优化 (后{len(iterations)-init_points}次)’, markersize8, alpha0.7)ax2.axvline(xinit_points, color‘red’, linestyle‘–’, alpha0.5, label‘探索→利用’)ax2.set_xlabel(‘迭代次数’, fontsize12)ax2.set_ylabel(‘准确率’, fontsize12)ax2.set_title(‘探索阶段 vs 利用阶段 (SVM)’, fontsize14, fontweight‘bold’)ax2.legend()ax2.grid(True, alpha0.3)plt.tight_layout()plt.show()输出统计信息print(f\n总迭代次数: {len(scores)}“)print(f最低得分: {min(scores):.4f}”)print(f最高得分: {max(scores):.4f}“)print(f平均得分: {np.mean(scores):.4f}”)print(f得分标准差: {np.std(scores):.4f}“)print(f得分提升: {max(scores) - scores[0]:.4f}”)print(“\n最优参数组合:”, optimizer.max[‘params’])