机器学习面试实战:用 Python 代码解析 5 个经典算法问题
机器学习面试实战:用 Python 代码解析 5 个经典算法问题
1. 缺失值处理的实战策略与代码实现
在真实数据集中,缺失值如同隐藏在数据矩阵中的"黑洞",直接影响模型的训练效果。以下是三种主流处理方法的 Python 实现:
import pandas as pd import numpy as np from sklearn.impute import SimpleImputer, KNNImputer # 创建含缺失值的示例数据 data = {'Age': [25, np.nan, 35, 40, np.nan], 'Income': [50000, 60000, np.nan, 80000, 90000]} df = pd.DataFrame(data) # 方法1:均值填充 mean_imputer = SimpleImputer(strategy='mean') df_mean = pd.DataFrame(mean_imputer.fit_transform(df), columns=df.columns) # 方法2:KNN填充 knn_imputer = KNNImputer(n_neighbors=2) df_knn = pd.DataFrame(knn_imputer.fit_transform(df), columns=df.columns) # 方法3:构建缺失指示特征 df_indicator = df.copy() for col in df.columns: df_indicator[f'{col}_missing'] = df[col].isnull().astype(int)关键决策因素对比表:
| 处理方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 均值填充 | 数值型特征,缺失随机 | 计算简单,保持均值稳定 | 扭曲数据分布,忽略特征相关性 |
| KNN填充 | 特征间存在相关性 | 利用特征间关系,更精确 | 计算成本高,需调参 |
| 缺失指示 | 非随机缺失(MAR) | 保留缺失模式信息 | 增加特征维度 |
提示:在金融风控场景中,缺失本身可能是重要特征(如收入信息缺失可能反映特定人群),此时缺失指示器方法尤为有效。
2. 特征工程的自动化实现技巧
特征工程是模型效果的"催化剂",以下代码展示如何通过Pipeline实现自动化特征处理:
from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.compose import ColumnTransformer from sklearn.feature_selection import SelectKBest, f_classif # 数值型特征处理流程 numeric_features = ['Age', 'Income'] numeric_transformer = Pipeline(steps=[ ('imputer', SimpleImputer(strategy='median')), ('scaler', StandardScaler())]) # 类别型特征处理流程 categorical_features = ['Gender', 'Education'] categorical_transformer = Pipeline(steps=[ ('imputer', SimpleImputer(strategy='constant', fill_value='missing')), ('onehot', OneHotEncoder(handle_unknown='ignore'))]) # 组合特征处理器 preprocessor = ColumnTransformer( transformers=[ ('num', numeric_transformer, numeric_features), ('cat', categorical_transformer, categorical_features)]) # 完整Pipeline包含特征选择 full_pipeline = Pipeline(steps=[ ('preprocessor', preprocessor), ('feature_selection', SelectKBest(score_func=f_classif, k=10)), ('classifier', RandomForestClassifier())])特征生成技巧清单:
- 交互特征:
df['Age_Income'] = df['Age'] * df['Income'] - 分箱特征:
pd.cut(df['Age'], bins=5, labels=False) - 统计特征:
df.groupby('Group')['Value'].transform('mean') - 时间特征:
df['DayOfWeek'] = df['Date'].dt.dayofweek
3. 模型评估的全面诊断方案
超越简单的准确率指标,我们需要建立多维度的评估体系:
from sklearn.metrics import classification_report, roc_auc_score from sklearn.model_selection import learning_curve import matplotlib.pyplot as plt def comprehensive_evaluation(model, X, y): # 基础分类报告 y_pred = model.predict(X) print(classification_report(y, y_pred)) # ROC曲线绘制 y_proba = model.predict_proba(X)[:,1] fpr, tpr, _ = roc_curve(y, y_proba) plt.plot(fpr, tpr) plt.title(f'ROC Curve (AUC={roc_auc_score(y, y_proba):.3f})') # 学习曲线分析 train_sizes, train_scores, test_scores = learning_curve( model, X, y, cv=5, scoring='accuracy') plt.figure() plt.plot(train_sizes, np.mean(train_scores, axis=1), label='Training score') plt.plot(train_sizes, np.mean(test_scores, axis=1), label='Cross-validation score') plt.legend()模型诊断决策矩阵:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 训练集表现远优于测试集 | 过拟合 | 增加正则化、简化模型、获取更多数据 |
| 训练/测试集表现均差 | 欠拟合 | 增加特征、增强模型复杂度、减少正则化 |
| 验证曲线波动大 | 数据量不足 | 增加训练数据、使用交叉验证 |
| AUC值低于0.7 | 特征区分度不足 | 特征工程、尝试不同算法 |
4. 超参数优化的智能搜索方法
告别网格搜索的低效,现代优化技术可以节省90%的计算时间:
from sklearn.model_selection import RandomizedSearchCV from scipy.stats import loguniform # 定义参数分布 param_dist = { 'n_estimators': [50, 100, 200], 'max_depth': [None, 10, 20, 30], 'min_samples_split': loguniform(0.01, 0.2), 'max_features': ['sqrt', 'log2'] } # 随机搜索 search = RandomizedSearchCV( RandomForestClassifier(), param_distributions=param_dist, n_iter=50, cv=5, scoring='roc_auc', n_jobs=-1 ) search.fit(X_train, y_train) # 最优参数输出 print(f"Best params: {search.best_params_}") print(f"Best score: {search.best_score_:.3f}")优化策略对比分析:
| 方法 | 原理 | 优点 | 适用场景 |
|---|---|---|---|
| 网格搜索 | 参数空间穷举 | 找到全局最优 | 小参数空间 |
| 随机搜索 | 参数随机采样 | 高效,适合高维空间 | 中等参数空间 |
| 贝叶斯优化 | 建立概率模型 | 智能导向最优区域 | 计算成本高的模型 |
| 进化算法 | 模拟自然选择 | 处理非线性关系 | 复杂参数空间 |
5. 模型解释的实战技巧
黑箱模型需要解释性工具来建立业务信任:
import shap import lime from eli5 import show_weights # SHAP全局解释 explainer = shap.TreeExplainer(model) shap_values = explainer.shap_values(X) shap.summary_plot(shap_values, X) # LIME局部解释 explainer = lime.lime_tabular.LimeTabularExplainer( training_data=X.values, feature_names=X.columns, class_names=['No', 'Yes'], mode='classification') exp = explainer.explain_instance(X.iloc[0], model.predict_proba) exp.show_in_notebook() # ELI5特征重要性 show_weights(model, feature_names=X.columns.tolist())解释方法选择指南:
全局解释(理解整体特征影响):
- SHAP:精确但计算成本高
- 特征重要性:快速但忽略交互作用
局部解释(分析单个预测):
- LIME:适合任意模型,近似解释
- SHAP force plot:展示特征贡献方向
业务报告:
- 特征影响排序表
- 决策路径可视化
- 反事实分析示例
在金融风控的实际项目中,我们发现收入与年龄的交互特征对信用评分影响显著,通过SHAP分析发现其非线性关系,进而优化了评分卡模型的分箱策略。这种基于解释的迭代改进使模型KS值提升了15%。