1. 项目概述为什么需要一个“通用模板”每次数学建模比赛或者接到一个数据分析项目你是不是也经历过这样的循环拿到题目和数据脑子里一片空白不知道从哪里下手好不容易理清思路开始写代码又在数据预处理、特征工程、模型选择和调参之间反复横跳代码越写越乱最后自己都看不懂等到要写论文或者报告了又得回头从一堆混乱的脚本里扒拉结果和图表。整个过程耗时耗力还容易出错。我做了十多年的数据科学项目带过不少学生打数模发现新手和老手最大的区别往往不在于掌握了多少高深的算法而在于有没有一套清晰、可复用、能保证基础质量的工作流。这就是“使用 sklearn 进行数学建模的通用模板”的价值所在。它不是一个能解决所有问题的“银弹”而是一个结构化的脚手架。它的核心目标是帮你把建模过程标准化从数据加载到模型评估每一步都井井有条。无论你是面对“2025国赛C题”这样的复杂赛题还是处理“大学生择业选择”这类实际问题这个模板都能确保你的基础流程不出错把宝贵的精力集中在问题分析、特征构造和模型创新这些真正能拉开差距的地方。sklearnScikit-learn作为Python机器学习的事实标准库其API设计本身就非常一致fit,transform,predict这为我们构建模板提供了绝佳的基础。这个模板适合所有使用Python进行数据分析、机器学习建模的初学者和中级从业者它能帮你快速搭建一个稳健的基线模型并在此之上进行高效迭代。2. 模板整体架构与设计哲学一个健壮的建模流程绝不能是东一榔头西一棒子的脚本堆砌。我设计的这个通用模板其核心思想是“管道化”和“模块化”。整个流程被抽象为几个顺序执行的、高内聚低耦合的模块数据像流水一样经过这些模块被逐步加工成最终的模型预测结果。2.1 核心流程模块拆解整个模板围绕一个主函数或一个Jupyter Notebook的单元格顺序展开主要包含以下六大模块环境准备与数据加载解决“在哪里跑”和“数据从哪里来”的问题。探索性数据分析解决“数据长什么样”的问题这是所有后续决策的基础。数据预处理与特征工程解决“如何把数据喂给模型”的问题这是影响模型性能的关键。模型训练与验证解决“选哪个模型、怎么调参”的问题。模型评估与优化解决“模型好不好、怎么变得更好”的问题。结果输出与持久化解决“如何交付和复用成果”的问题。这个流程是单向且迭代的。例如在特征工程后我们可能需要对模型进行初步评估然后根据结果返回去调整特征或者在模型评估后返回去调整预处理参数。模板提供了清晰的节点让你知道当前处于哪个阶段以及可以回溯到哪个阶段进行调整。2.2 为什么选择这样的架构可复现性每一步操作从数据清洗到模型参数都被清晰地记录和封装。三个月后你甚至你的队友都能一键复现整个实验。可维护性当需要修改特征工程方法或尝试新模型时你只需要在对应的模块内改动而不会“牵一发而动全身”把整个代码搞乱。效率提升避免了每次从头开始写import、读数据、划分训练测试集的重复劳动。模板帮你做好了这些“脏活累活”让你能快速进入核心的建模环节。减少错误标准化的流程减少了因步骤遗漏比如忘了做特征缩放而导致的低级错误。注意模板的“通用性”体现在流程框架和接口上而不是具体的算法。你需要根据具体问题比如是分类、回归还是聚类填充每个模块的具体内容。例如2024年高教杯B题可能涉及时间序列预测那么特征工程模块就需要引入滞后特征、滑动窗口统计等。3. 环境准备与数据加载模块详解万事开头难一个稳定的环境是成功的一半。很多奇怪的报错追根溯源都是环境依赖冲突。3.1 环境依赖管理我强烈建议为每一个数学建模项目或数据分析任务创建独立的虚拟环境。这能保证项目依赖的纯净性。使用conda或venv均可。# 使用 conda 创建环境推荐尤其对Windows用户友好 conda create -n math_modeling_2025 python3.9 conda activate math_modeling_2025 # 使用 venv 创建环境 python -m venv venv_math_modeling # Windows venv_math_modeling\Scripts\activate # Linux/Mac source venv_math_modeling/bin/activate创建环境后将核心依赖写入requirements.txt文件# requirements.txt scikit-learn1.3.0 pandas1.5.0 numpy1.23.0 matplotlib3.6.0 seaborn0.12.0 jupyter1.0.0 # 可选用于更高级的统计分析或可视化 scipy1.9.0 statsmodels0.13.0然后使用pip install -r requirements.txt一键安装。在代码开头我们集中导入这些库并做好基础设置。# 模块1: 环境准备与数据加载 import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn import __version__ as sklearn_version # 设置绘图风格和显示选项让图表更好看输出更完整 plt.style.use(seaborn-v0_8-whitegrid) # 使用seaborn的网格风格 sns.set_palette(husl) # 设置颜色盘 pd.set_option(display.max_columns, None) # 显示所有列 pd.set_option(display.float_format, {:.4f}.format) # 浮点数显示格式 print(fSklearn Version: {sklearn_version})3.2 数据加载的多种场景处理数学建模中的数据来源五花八门可能是CSV、Excel也可能是数据库或API。模板需要兼容这些情况。def load_data(file_path, file_typecsv, **kwargs): 通用数据加载函数 Args: file_path: 文件路径或数据库连接字符串 file_type: 文件类型支持 csv, excel, sql **kwargs: 传递给对应pandas读取函数的参数 Returns: pandas DataFrame if file_type csv: df pd.read_csv(file_path, **kwargs) elif file_type excel: df pd.read_excel(file_path, **kwargs) elif file_type sql: # 假设已创建数据库引擎 engine query kwargs.get(query, SELECT * FROM table) df pd.read_sql(query, conkwargs.get(con)) else: raise ValueError(fUnsupported file type: {file_type}) print(f数据加载成功形状: {df.shape}) print(f列名: {df.columns.tolist()}) return df # 使用示例 # df load_data(2025_problem_c_data.csv) # df load_data(data.xlsx, file_typeexcel, sheet_nameSheet1)加载数据后第一时间使用df.head()、df.info()和df.describe()进行快速浏览了解数据规模、类型和基本统计信息。这是探索性数据分析的开始但我们在下一个模块会系统化地进行。4. 探索性数据分析的系统化方法EDA不是简单的画几个图而是带着问题去审视数据为后续的预处理和建模提供决策依据。我习惯将EDA分为三个层次单变量分析、双变量分析和多变量分析。4.1 单变量分析了解每一个“士兵”目标是了解每个特征的分布、中心趋势、离散程度以及缺失情况。def univariate_analysis(df, target_colNone): 单变量分析 print(*50) print(1. 数据基本信息) print(*50) print(df.info()) print(\n *50) print(2. 描述性统计数值型) print(*50) print(df.describe()) print(\n *50) print(3. 描述性统计分类型) print(*50) categorical_cols df.select_dtypes(include[object, category]).columns for col in categorical_cols: print(f\n--- {col} ---) print(df[col].value_counts(dropnaFalse).head(10)) # 看前10个最常见的值 print(f唯一值数量: {df[col].nunique()}) print(\n *50) print(4. 缺失值统计) print(*50) missing_stats df.isnull().sum() missing_stats missing_stats[missing_stats 0].sort_values(ascendingFalse) if len(missing_stats) 0: print(missing_stats) # 可视化缺失值 import missingno as msno # 需要安装 missingno msno.matrix(df) plt.title(Missing Values Matrix) plt.show() else: print(无缺失值。) print(\n *50) print(5. 数值型特征分布可视化) print(*50) numeric_cols df.select_dtypes(include[np.number]).columns # 为避免图形过多只绘制部分特征或使用子图 cols_to_plot numeric_cols[:min(6, len(numeric_cols))] # 最多画6个 fig, axes plt.subplots(2, 3, figsize(15, 8)) axes axes.ravel() for idx, col in enumerate(cols_to_plot): axes[idx].hist(df[col].dropna(), bins30, edgecolorblack, alpha0.7) axes[idx].set_title(fDistribution of {col}) axes[idx].set_xlabel(col) axes[idx].set_ylabel(Frequency) plt.tight_layout() plt.show()4.2 双变量分析寻找特征与目标的关系这是建模前最关键的一步帮助我们初步判断哪些特征可能重要。def bivariate_analysis(df, target_col): 双变量分析特征与目标变量的关系 Args: df: DataFrame target_col: 目标变量列名 if target_col not in df.columns: raise ValueError(f目标列 {target_col} 不在DataFrame中。) target_type numeric if pd.api.types.is_numeric_dtype(df[target_col]) else categorical numeric_features df.select_dtypes(include[np.number]).columns.drop(target_col, errorsignore) categorical_features df.select_dtypes(include[object, category]).columns.drop(target_col, errorsignore) print(*50) print(f目标变量 {target_col} 与特征的关系分析) print(*50) # 情况1: 目标变量是数值型回归问题 if target_type numeric: print(\n--- 数值型特征与目标的相关性 ---) corr_with_target df[numeric_features].corrwith(df[target_col]).sort_values(ascendingFalse) print(corr_with_target) # 绘制相关性最高的几个特征与目标的散点图 top_n min(4, len(corr_with_target)) top_features corr_with_target.index[:top_n] fig, axes plt.subplots(2, 2, figsize(12, 8)) axes axes.ravel() for idx, feat in enumerate(top_features): axes[idx].scatter(df[feat], df[target_col], alpha0.5) axes[idx].set_xlabel(feat) axes[idx].set_ylabel(target_col) axes[idx].set_title(f{feat} vs {target_col}\nCorr: {corr_with_target[feat]:.3f}) plt.tight_layout() plt.show() # 对于分类特征可以看不同类别下目标变量的分布箱线图 if len(categorical_features) 0: cat_to_plot categorical_features[:min(2, len(categorical_features))] for cat_feat in cat_to_plot: # 如果类别太多取前N个主要的类别 top_categories df[cat_feat].value_counts().index[:10] df_plot df[df[cat_feat].isin(top_categories)] plt.figure(figsize(10, 6)) sns.boxplot(xcat_feat, ytarget_col, datadf_plot) plt.title(fDistribution of {target_col} across {cat_feat}) plt.xticks(rotation45) plt.show() # 情况2: 目标变量是分类型分类问题 else: print(f\n目标变量 {target_col} 的类别分布:) print(df[target_col].value_counts()) # 对于数值型特征绘制不同目标类别下的分布小提琴图或箱线图 if len(numeric_features) 0: feat_to_plot numeric_features[:min(4, len(numeric_features))] for feat in feat_to_plot: plt.figure(figsize(8, 5)) sns.violinplot(xtarget_col, yfeat, datadf, innerquartile) plt.title(fDistribution of {feat} by {target_col}) plt.show() # 对于分类特征可以使用交叉表或堆叠柱状图 if len(categorical_features) 0: cat_to_plot categorical_features[:min(2, len(categorical_features))] for cat_feat in cat_to_plot: cross_tab pd.crosstab(df[cat_feat], df[target_col], normalizeindex) # 行百分比 cross_tab.plot(kindbar, stackedTrue, figsize(10, 6)) plt.title(fRelationship between {cat_feat} and {target_col}) plt.ylabel(Proportion) plt.legend(titletarget_col, bbox_to_anchor(1.05, 1), locupper left) plt.tight_layout() plt.show()4.3 多变量分析与洞察记录在完成单变量和双变量分析后你需要将发现记录下来形成一份“数据洞察备忘录”。这个备忘录将直接指导下一步的预处理和特征工程。你可以创建一个Markdown单元格或文本文件记录如下内容数据质量哪些列有缺失缺失比例如何是随机缺失还是系统缺失例如收入字段的缺失可能意味着高收入人群不愿透露。特征分布哪些特征是偏态分布是否存在量纲差异巨大的特征这决定了是否需要标准化/归一化。特征与目标关系哪些特征与目标变量相关性高哪些分类特征对目标区分度大潜在问题是否存在异常值是否有高度相关的特征多重共线性分类特征的类别是否过多高基数初步特征工程想法是否需要创建交互特征、分箱、编码这个备忘录是你思考过程的结晶也是与队友沟通和论文写作的重要素材。很多优秀的数学建模论文其“问题分析”和“模型假设”部分就源于扎实的EDA。5. 数据预处理与特征工程管道构建这是将原始数据转化为模型“可口食物”的关键步骤。sklearn的Pipeline和ColumnTransformer是构建自动化、可复现预处理流程的神器。5.1 数据清洗与缺失值处理策略根据EDA的发现制定清洗策略。切忌无脑填充缺失值要思考缺失的机制。from sklearn.impute import SimpleImputer, KNNImputer from sklearn.experimental import enable_iterative_imputer from sklearn.impute import IterativeImputer def get_imputation_strategy(df, col, strategymedian): 根据列的数据类型和业务逻辑返回合适的填充策略。 实际应用中这个函数会更复杂可能包含基于其他列的规则。 # 示例对于数值列默认用中位数填充对于分类列用众数填充。 if pd.api.types.is_numeric_dtype(df[col]): if strategy mean: return SimpleImputer(strategymean) elif strategy median: return SimpleImputer(strategymedian) elif strategy knn: return KNNImputer(n_neighbors5) elif strategy iterative: return IterativeImputer(max_iter10, random_state42) else: return SimpleImputer(strategyconstant, fill_value0) # 默认填0 else: # 分类列 return SimpleImputer(strategymost_frequent)5.2 特征编码与缩放模型只能处理数值。对于分类变量必须编码。不同模型对特征的尺度敏感度不同。from sklearn.preprocessing import ( StandardScaler, MinMaxScaler, RobustScaler, OneHotEncoder, OrdinalEncoder, LabelEncoder ) from sklearn.compose import ColumnTransformer # 假设我们有以下列定义根据EDA结果调整 numeric_features [age, income, credit_score] categorical_features_low_card [education, marital_status] # 低基数分类特征 categorical_features_high_card [zip_code] # 高基数分类特征需要特殊处理 target loan_default # 构建列转换器 preprocessor ColumnTransformer( transformers[ # 数值特征使用RobustScaler对异常值不敏感 (num, RobustScaler(), numeric_features), # 低基数分类特征使用One-Hot编码 (cat_low, OneHotEncoder(handle_unknownignore, sparse_outputFalse), categorical_features_low_card), # 高基数分类特征使用目标编码或频率编码这里用频率编码示例 # 注意目标编码需要在Pipeline中小心处理避免数据泄露。这里先展示频率编码。 (cat_high, passthrough, categorical_features_high_card) # 暂时保留后续单独处理 ], remainderdrop # 丢弃未指定的列 ) # 对于高基数特征我们可以在Pipeline之外先进行转换 # 例如频率编码 df[zip_code_freq] df[zip_code].map(df[zip_code].value_counts(normalizeTrue)) # 然后更新 numeric_features将 zip_code_freq 加入并从原始特征中移除 zip_code5.3 特征构造从数据中挖掘“金矿”这是体现建模者水平的地方。好的特征往往比复杂的模型更有效。特征构造需要结合领域知识和数据分析直觉。交互特征例如在电商推荐中“用户活跃度” × “商品热度”。多项式特征对于回归问题PolynomialFeatures可以自动生成特征的高次项和交互项但要小心维度爆炸。分箱将连续变量离散化可以捕捉非线性关系。例如将年龄分为“青年”、“中年”、“老年”。时间序列特征如果是时间数据可以构造滞后项、滑动窗口均值、时序趋势等。文本特征如果是文本数据使用TF-IDF、词向量等。from sklearn.preprocessing import PolynomialFeatures from sklearn.decomposition import PCA # 示例创建多项式特征通常只用于数值特征 poly PolynomialFeatures(degree2, interaction_onlyTrue, include_biasFalse) # interaction_onlyTrue 表示只生成交互项不生成平方项防止共线性。 # 示例使用PCA进行特征降维在特征很多且相关性强时使用 pca PCA(n_components0.95) # 保留95%的方差实操心得特征工程不是一蹴而就的。我通常采用“贪心法”先使用基础特征原始特征简单清洗训练一个基线模型。基于模型结果如特征重要性和业务理解构造一批新特征。将新特征加入重新训练模型观察性能提升。如果提升显著保留该特征否则舍弃。如此迭代。6. 模型训练、验证与调参的标准化流程有了干净的特征就可以开始训练模型了。这一步的核心是避免过拟合和公平评估。6.1 数据划分与交叉验证永远不要在训练模型的数据上评估模型那会得到过于乐观的结果。from sklearn.model_selection import train_test_split, cross_val_score, StratifiedKFold, KFold # 假设 X 是特征矩阵y 是目标向量 X df.drop(columns[target]) y df[target] # 基础划分训练集和测试集 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy # 分类问题建议使用分层抽样 ) # 更稳健的评估交叉验证 # 对于分类问题使用 StratifiedKFold 保持类别比例 if y.nunique() 10: # 粗略判断为分类问题 cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) else: cv KFold(n_splits5, shuffleTrue, random_state42) # 使用交叉验证评估一个模型 from sklearn.ensemble import RandomForestClassifier base_model RandomForestClassifier(n_estimators100, random_state42) cv_scores cross_val_score(base_model, X_train, y_train, cvcv, scoringaccuracy) print(f交叉验证平均准确率: {cv_scores.mean():.4f} (/- {cv_scores.std()*2:.4f}))6.2 构建完整的建模管道将预处理和模型训练封装进一个Pipeline这是最佳实践。from sklearn.pipeline import Pipeline from sklearn.ensemble import RandomForestClassifier from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC # 定义预处理步骤使用之前定义的 preprocessor # 定义多个候选模型 pipelines { rf: Pipeline(steps[ (preprocessor, preprocessor), (classifier, RandomForestClassifier(random_state42)) ]), lr: Pipeline(steps[ (preprocessor, preprocessor), (classifier, LogisticRegression(max_iter1000, random_state42)) ]), svm: Pipeline(steps[ (preprocessor, preprocessor), (classifier, SVC(probabilityTrue, random_state42)) # probabilityTrue 用于后续绘制ROC曲线 ]) } # 快速评估多个模型 for name, pipeline in pipelines.items(): cv_scores cross_val_score(pipeline, X_train, y_train, cvcv, scoringaccuracy) print(f{name:3s} - 平均准确率: {cv_scores.mean():.4f} (/- {cv_scores.std()*2:.4f}))6.3 超参数调优让模型性能更上一层楼模型有很多“旋钮”超参数需要调整到最佳位置。GridSearchCV或RandomizedSearchCV是自动化调参的工具。from sklearn.model_selection import GridSearchCV # 以随机森林为例定义参数网格 param_grid_rf { classifier__n_estimators: [100, 200, 300], classifier__max_depth: [10, 20, None], classifier__min_samples_split: [2, 5, 10], classifier__min_samples_leaf: [1, 2, 4] } # 创建 GridSearchCV 对象 grid_search_rf GridSearchCV( estimatorpipelines[rf], param_gridparam_grid_rf, cvcv, scoringaccuracy, n_jobs-1, # 使用所有CPU核心 verbose1 ) # 在训练集上进行网格搜索 print(开始随机森林网格搜索...) grid_search_rf.fit(X_train, y_train) print(f\n最佳参数: {grid_search_rf.best_params_}) print(f最佳交叉验证分数: {grid_search_rf.best_score_:.4f}) # 获取最佳模型 best_rf_model grid_search_rf.best_estimator_注意RandomizedSearchCV在参数空间较大时比GridSearchCV更高效它随机采样参数组合进行尝试。对于大型数据集或复杂模型建议先用RandomizedSearchCV缩小范围再用GridSearchCV精细调整。7. 模型评估与结果分析的全面视角模型训练好了怎么知道它好不好不能只看准确率。尤其是对于类别不平衡的数据比如欺诈检测正常交易远多于欺诈交易准确率可能是骗人的。7.1 多维度评估指标根据问题类型选择合适的评估指标。from sklearn.metrics import ( accuracy_score, precision_score, recall_score, f1_score, roc_auc_score, confusion_matrix, classification_report, mean_absolute_error, mean_squared_error, r2_score ) def evaluate_classification_model(model, X_test, y_test, model_nameModel): 评估分类模型输出多种指标和图表。 y_pred model.predict(X_test) y_pred_proba model.predict_proba(X_test)[:, 1] if hasattr(model, predict_proba) else None print(f\n{*60}) print(f评估报告 - {model_name}) print(f{*60}) # 基础指标 accuracy accuracy_score(y_test, y_pred) precision precision_score(y_test, y_pred, averageweighted) # 对于多分类使用加权平均 recall recall_score(y_test, y_pred, averageweighted) f1 f1_score(y_test, y_pred, averageweighted) print(f准确率 (Accuracy): {accuracy:.4f}) print(f精确率 (Precision): {precision:.4f}) print(f召回率 (Recall): {recall:.4f}) print(fF1 分数: {f1:.4f}) if y_pred_proba is not None and len(np.unique(y_test)) 2: # 二分类问题计算AUC auc roc_auc_score(y_test, y_pred_proba) print(fAUC 分数: {auc:.4f}) # 详细分类报告 print(\n详细分类报告:) print(classification_report(y_test, y_pred, target_names[fClass {i} for i in np.unique(y_test)])) # 混淆矩阵热力图 cm confusion_matrix(y_test, y_pred) plt.figure(figsize(8,6)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsnp.unique(y_test), yticklabelsnp.unique(y_test)) plt.title(fConfusion Matrix - {model_name}) plt.ylabel(True Label) plt.xlabel(Predicted Label) plt.tight_layout() plt.show() # ROC 曲线 (仅二分类) if y_pred_proba is not None and len(np.unique(y_test)) 2: from sklearn.metrics import roc_curve fpr, tpr, thresholds roc_curve(y_test, y_pred_proba) plt.figure(figsize(8,6)) plt.plot(fpr, tpr, labelf{model_name} (AUC {auc:.3f})) plt.plot([0, 1], [0, 1], k--, labelRandom Guess) plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.xlabel(False Positive Rate) plt.ylabel(True Positive Rate) plt.title(fROC Curve - {model_name}) plt.legend(loclower right) plt.grid(True, alpha0.3) plt.show() return { accuracy: accuracy, precision: precision, recall: recall, f1: f1, auc: auc if auc in locals() else None } # 使用最佳模型在测试集上评估 test_metrics evaluate_classification_model(best_rf_model, X_test, y_test, model_nameOptimized Random Forest)对于回归问题评估函数类似但指标换为MAE,MSE,RMSE,R²可视化则使用真实值 vs 预测值的散点图或残差图。7.2 特征重要性分析理解模型为什么做出预测有时比预测本身更重要。这对于数学建模论文中的“模型解释”部分至关重要。# 对于树模型如随机森林、XGBoost可以获取特征重要性 if hasattr(best_rf_model.named_steps[classifier], feature_importances_): # 获取预处理后的特征名称对于OneHot编码名称会扩展 # 注意ColumnTransformer 转换后的特征名需要手动提取稍复杂 # 这里提供一个简化示例假设我们能够获得特征名列表 feature_names importances best_rf_model.named_steps[classifier].feature_importances_ # 假设我们有一个函数能获取 pipeline 最终的特征名 # feature_names get_feature_names_from_pipeline(best_rf_model[preprocessor]) # 这里用占位符 feature_names [ffeature_{i} for i in range(len(importances))] # 创建重要性 DataFrame feat_imp_df pd.DataFrame({ feature: feature_names, importance: importances }).sort_values(importance, ascendingFalse) # 可视化 top N 特征 top_n 20 plt.figure(figsize(10, 6)) sns.barplot(ximportance, yfeature, datafeat_imp_df.head(top_n)) plt.title(fTop {top_n} Feature Importances (Random Forest)) plt.tight_layout() plt.show() print(\n特征重要性 Top 10:) print(feat_imp_df.head(10))实操心得模型评估后如果效果不理想不要急于换更复杂的模型。回头检查数据问题EDA是否充分特征工程是否到位有没有信息泄露评估方式问题指标选对了吗测试集划分是否合理交叉验证过程是否正确简单模型基线逻辑回归/线性回归这种简单模型的基线分数是多少你的复杂模型比它好多少如果好得不多可能说明特征本身的信息量有限。8. 模型部署、持久化与报告生成模型通过测试后工作还没结束。你需要保存模型并生成可交付的结果。8.1 模型持久化使用joblib对于sklearn模型通常比pickle更高效保存训练好的管道。import joblib import os # 创建保存模型的目录 model_dir saved_models os.makedirs(model_dir, exist_okTrue) # 保存最佳模型管道 model_path os.path.join(model_dir, best_loan_default_model.pkl) joblib.dump(best_rf_model, model_path) print(f模型已保存至: {model_path}) # 加载模型在另一个脚本或环境中 # loaded_model joblib.load(model_path) # new_predictions loaded_model.predict(new_data)8.2 结果输出与报告对于数学建模最终需要提交论文和可能的结果文件。def generate_predictions_and_report(model, X_test, y_test, output_dirresults): 生成预测结果和评估报告文件。 os.makedirs(output_dir, exist_okTrue) # 1. 在测试集上进行预测 y_pred model.predict(X_test) y_pred_proba model.predict_proba(X_test) if hasattr(model, predict_proba) else None # 2. 保存预测结果到CSV results_df X_test.copy() results_df[true_label] y_test.values results_df[predicted_label] y_pred if y_pred_proba is not None: # 保存每个类别的预测概率 for i in range(y_pred_proba.shape[1]): results_df[fpred_prob_class_{i}] y_pred_proba[:, i] results_path os.path.join(output_dir, test_set_predictions.csv) results_df.to_csv(results_path, indexFalse) print(f预测结果已保存至: {results_path}) # 3. 生成文本格式的评估报告 report_path os.path.join(output_dir, model_evaluation_report.txt) with open(report_path, w) as f: f.write(*60 \n) f.write(模型评估报告\n) f.write(*60 \n\n) f.write(f模型类型: {type(model.named_steps[classifier]).__name__}\n) f.write(f训练数据量: {len(X_train)}\n) f.write(f测试数据量: {len(X_test)}\n\n) from sklearn.metrics import classification_report report_str classification_report(y_test, y_pred) f.write(分类报告:\n) f.write(report_str) f.write(\n) f.write(混淆矩阵:\n) cm confusion_matrix(y_test, y_pred) f.write(np.array2string(cm)) print(f评估报告已保存至: {report_path}) # 4. 生成关键图表并保存 fig, axes plt.subplots(1, 2, figsize(14, 5)) # 混淆矩阵热力图 sns.heatmap(cm, annotTrue, fmtd, cmapBlues, axaxes[0]) axes[0].set_title(Confusion Matrix) axes[0].set_ylabel(True Label) axes[0].set_xlabel(Predicted Label) # 特征重要性图 (如果可用) if hasattr(model.named_steps[classifier], feature_importances_): importances model.named_steps[classifier].feature_importances_ # ... (获取特征名并排序的代码同上) # 这里简化处理 indices np.argsort(importances)[-10:] # 取最重要的10个 axes[1].barh(range(len(indices)), importances[indices]) axes[1].set_yticks(range(len(indices))) # axes[1].set_yticklabels([feature_names[i] for i in indices]) # 需要特征名 axes[1].set_xlabel(Feature Importance) axes[1].set_title(Top 10 Feature Importances) else: axes[1].text(0.5, 0.5, Feature Importance\nNot Available, hacenter, vacenter, fontsize12) axes[1].set_title(Feature Importance) plt.tight_layout() chart_path os.path.join(output_dir, evaluation_charts.png) plt.savefig(chart_path, dpi300, bbox_inchestight) plt.close(fig) # 关闭图形避免在Notebook中重复显示 print(f评估图表已保存至: {chart_path}) # 调用函数生成报告 generate_predictions_and_report(best_rf_model, X_test, y_test)这个模板从数据到报告形成了一个完整的闭环。它最大的价值在于提供了结构迫使你按科学的步骤思考和工作。在实际的数学建模竞赛中你可能需要针对赛题特点如“2026亚太杯数学建模A题”可能涉及优化决策“2024高教杯数学建模B题”可能涉及评价体系调整模板中的某些模块例如增加专门的评价模型模块或优化求解模块。但万变不离其宗这个以sklearn Pipeline为核心的标准化工作流能确保你的基础建模部分扎实、高效、可复现让你有更多时间去攻克问题最核心的难点。记住好的工具和流程不会限制你的创造力而是为你腾出思考的空间。