机器学习笔记(二)模型评估与特征工程实操

机器学习笔记(二)模型评估与特征工程实操

一、为什么需要模型评估

训练出来的模型准确率高,不代表它就是一个好模型。一个常见陷阱是过拟合:模型在训练集上表现完美,但面对新数据时一塌糊涂。模型评估的核心目标是回答一个问题——这个模型能不能在未知数据上稳定可靠地工作

1.1 过拟合 vs 欠拟合

现象表现原因解决方案
过拟合训练集准、测试集差模型太复杂增加数据、正则化、降低复杂度
欠拟合训练集和测试集都差模型太简单增加特征、换更复杂模型

1.2 评估指标体系

不同任务需要不同的评估指标,准确率不是万能的

指标公式适用场景
准确率正确数 / 总数类别均衡
精确率TP / (TP + FP)关注误报代价(垃圾邮件)
召回率TP / (TP + FN)关注漏报代价(疾病检测)
F1值精确率与召回率的调和平均精确率与召回率需兼顾

TP = 真正例,FP = 假正例,FN = 假负例,TN = 真负例

二、交叉验证实操

2.1 为什么简单划分不够

单次 train_test_split 的结果受随机种子影响,可能偏乐观或偏悲观。K 折交叉验证将数据分成 K 份,轮流用其中 1 份做测试、其余做训练,最终取平均,结果更可靠。

2.2 代码实操:K 折交叉验证

fromsklearn.datasetsimportload_breast_cancerfromsklearn.model_selectionimportcross_val_score,StratifiedKFoldfromsklearn.ensembleimportRandomForestClassifierfromsklearn.preprocessingimportStandardScalerfromsklearn.pipelineimportPipelineimportnumpyasnp# 加载数据data=load_breast_cancer()X,y=data.data,data.target# 用 Pipeline 封装标准化 + 模型,避免数据泄露pipeline=Pipeline([('scaler',StandardScaler()),('rf',RandomForestClassifier(n_estimators=100,random_state=42))])# 5 折分层交叉验证cv=StratifiedKFold(n_splits=5,shuffle=True,random_state=42)scores=cross_val_score(pipeline,X,y,cv=cv,scoring='f1')print(f"各折 F1 值:{scores}")print(f"平均 F1 值:{scores.mean():.4f}+/-{scores.std():.4f}")

输出结果:

各折 F1 值: [0.9722 0.9722 0.9861 0.9653 0.9861] 平均 F1 值: 0.9764 +/- 0.0080

2.3 学习曲线分析

学习曲线展示训练集大小与模型表现的关系,是诊断过拟合/欠拟合的利器:

fromsklearn.model_selectionimportlearning_curveimportmatplotlib.pyplotasplt train_sizes,train_scores,val_scores=learning_curve(pipeline,X,y,cv=5,train_sizes=np.linspace(0.1,1.0,10),scoring='f1',n_jobs=-1)train_mean=train_scores.mean(axis=1)val_mean=val_scores.mean(axis=1)plt.figure(figsize=(10,6))plt.plot(train_sizes,train_mean,'o-',color='#FF6B6B',label='Training F1')plt.plot(train_sizes,val_mean,'o-',color='#4D96FF',label='Validation F1')plt.xlabel('Training Set Size',fontsize=12)plt.ylabel('F1 Score',fontsize=12)plt.title('Learning Curve',fontsize=14)plt.legend(fontsize=12)plt.grid(True,alpha=0.3)plt.tight_layout()plt.savefig('learning_curve.png',dpi=150,bbox_inches='tight')plt.show()

如何判读学习曲线

  • 训练线高、验证线低,两线差距大 →过拟合
  • 两条线都低,差距小 →欠拟合
  • 两条线都高且接近 →理想状态

三、特征工程实操

3.1 特征工程的核心地位

业界有一句名言:数据和特征决定了机器学习的上限,模型和算法只是逼近这个上限。特征工程的质量直接决定最终效果。

3.2 数值型特征处理

importpandasaspdimportnumpyasnpfromsklearn.preprocessingimportStandardScaler,MinMaxScaler,RobustScaler# 模拟数据np.random.seed(42)data=pd.DataFrame({'age':np.random.normal(35,10,1000).clip(18,70),'income':np.random.lognormal(10,1,1000),# 偏态分布'score':np.random.uniform(0,100,1000)})# 方式一:标准化(均值为0,标准差为1)—— 适合大多数场景scaler_std=StandardScaler()data_std=scaler_std.fit_transform(data)# 方式二:归一化(缩放到0-1)—— 适合距离类算法scaler_minmax=MinMaxScaler()data_minmax=scaler_minmax.fit_transform(data)# 方式三:稳健缩放(用中位数和四分位距)—— 适合有离群值的数据scaler_robust=RobustScaler()data_robust=scaler_robust.fit_transform(data)

3.3 特征选择

fromsklearn.feature_selectionimportSelectKBest,f_classif,mutual_info_classiffromsklearn.ensembleimportRandomForestClassifier# 方式一:方差分析(F检验)选择 Top-K 特征selector_f=SelectKBest(f_classif,k=10)X_selected_f=selector_f.fit_transform(X,y)selected_features_f=data.feature_names[selector_f.get_support()]print("F检验选出的特征:",list(selected_features_f))# 方式二:随机森林特征重要性rf=RandomForestClassifier(n_estimators=100,random_state=42)rf.fit(X,y)importances=rf.feature_importances_ top10_idx=np.argsort(importances)[::-1][:10]print("\n随机森林 Top10 重要特征:")foriintop10_idx:print(f"{data.feature_names[i]:30s}{importances[i]:.4f}")# 方式三:互信息法(能捕捉非线性关系)selector_mi=SelectKBest(mutual_info_classif,k=10)X_selected_mi=selector_mi.fit_transform(X,y)selected_features_mi=data.feature_names[selector_mi.get_support()]print("\n互信息选出的特征:",list(selected_features_mi))

3.4 特征选择策略对比

方法原理优势局限
方差分析 F 检验线性相关性计算快只能发现线性关系
互信息法信息论统计量能发现非线性关系计算量较大
随机森林重要性分裂增益统计准确、通用需训练完整模型
递归特征消除 RFE逐步剔除效果好计算开销最大

四、综合实战:完整 Pipeline 流程

将上述知识整合为一个完整的机器学习 Pipeline,这也是实际项目中的标准做法:

fromsklearn.pipelineimportPipelinefromsklearn.model_selectionimportcross_val_score,GridSearchCVfromsklearn.preprocessingimportStandardScalerfromsklearn.feature_selectionimportSelectKBest,f_classiffromsklearn.ensembleimportRandomForestClassifierfromsklearn.datasetsimportload_breast_cancerimportnumpyasnp# 加载数据data=load_breast_cancer()X,y=data.data,data.target# 构建 Pipeline:标准化 -> 特征选择 -> 随机森林pipeline=Pipeline([('scaler',StandardScaler()),('feature_selection',SelectKBest(f_classif)),('classifier',RandomForestClassifier(random_state=42))])# 网格搜索调参param_grid={'feature_selection__k':[10,15,20,'all'],'classifier__n_estimators':[50,100,200],'classifier__max_depth':[4,6,8,None]}grid=GridSearchCV(pipeline,param_grid,cv=5,scoring='f1',n_jobs=-1)grid.fit(X,y)print(f"最佳参数:{grid.best_params_}")print(f"最佳 F1 值:{grid.best_score_:.4f}")# 查看参数组合的详细结果results=pd.DataFrame(grid.cv_results_)for_,rowinresults.nsmallest(5,'rank_test_score').iterrows():print(f"F1={row['mean_test_score']:.4f}| "f"k={row['params']['feature_selection__k']}, "f"n_est={row['params']['classifier__n_estimators']}, "f"depth={row['params']['classifier__max_depth']}")

五、小结

  • 模型评估不是可选项,交叉验证是衡量模型泛化能力的标准方法
  • 学习曲线是诊断过拟合/欠拟合的第一工具,比单纯看准确率更有价值
  • 特征工程决定模型上限,三种缩放方式各有所长,按数据特征选择
  • Pipeline将预处理、特征选择、模型训练封装为整体,既防止数据泄露又方便调参
  • 网格搜索 + 交叉验证是调参的黄金组合,实际项目中几乎必用