考试通知
Python机器学习全套代码详解:从数据处理到XGBoost建模 简介面向机器学习初学者与进阶开发者这份Python压缩包提供了GAM、GBDT、CART、BP、DNN等经典模型的训练代码与配套数据可直接用于数据建模与分析实践。包内共184个文件以117个ipynb代码脚本为主配合35个csv数据、13个txt说明、8个png图表、5个xlsx表单与1个json配置整体304.19MB。资源为每套代码匹配了独立数据集涵盖广义可加模型对非线性关系的拟合、梯度提升决策树的参数调优、决策树剪枝防止过拟合、BP神经网络结构搭建以及DNN深度学习框架应用并附有完整训练记录和可视化输出。已有110人浏览学习适合想通过动手代码掌握主流机器学习流程的读者从数据预处理、模型训练到预测输出均可直接复用或改写成自己的项目。1. 这套 Python 机器学习全套代码到底解决什么问题拿到一批业务数据要在两三天内给出能用的预测模型多数工程师第一反应不是从零写算法而是找一套能直接跑的 Python 机器学习全套代码做数据建模与分析。所谓“全套代码”不是一个玄学文件夹而是一条覆盖数据处理、特征工程、模型训练、结果分析的标准流水线复制过来换数据、调参数、看结论。这篇文章把这套流水线拆开讲透适合两类人刚入门想找个完整案例照抄的初学者以及在结构化数据里反复做建模但想规范流程的工程师。下面从环境准备一路写到避坑和模板化改造。2. Python 安装与代码结构让全套代码换台机器也能跑经常有人拿到一份机器学习代码第一步就是双击运行报错之后才开始翻 python 安装教程。我不建议这么干。数据建模与分析的项目核心要求不是“跑通一次”而是“换台机器、换个数据集也能稳定复现”。所以动手写第一行业务代码之前先把目录结构和运行环境定下来。这两件事占掉半天时间后面能省下无数个熬夜排查的晚上。2.1 按流程拆目录别把所有 .py 堆在一起“全套代码”不等于“一堆脚本”。我见过的能长期用的机器学习项目目录几乎都是按流程拆的而不是按算法拆。按算法拆的问题在于数据处理的代码散落在十几个文件里建模时改了一个清洗逻辑另一个脚本还在用旧数据最后模型结果对不上。按流程拆每个阶段的输入输出清清楚楚。我一般会搭一个这样的骨架目录/文件放什么为什么放在这data/原始数据和处理后的临时数据原始数据只读处理后数据统一出口src/数据处理、特征工程、模型训练的 .py核心逻辑集中按模块拆成 data_clean.py、features.py、train.pymodels/训练好的模型文件、评估结果模型和代码分离部署时只拿模型notebooks/探索性分析的 notebook实验放在 notebook 里正式代码进 srcconfig.py所有可调参数改参数不用翻代码这个结构不是标准答案但它服务一个目标任何一步出问题你知道该去哪翻、改了什么会影响什么。比如今天想把缺失值填充策略从均值换成中位数只需要改 src/data_clean.py 对应的函数然后重跑 train.py而不是在全项目里搜索 fillna。代码文件命名也建议带步骤编号比如 01_load_data.py、02_clean_data.py、03_train_model.py这样即使别人接手你的目录也能按文件名排出执行顺序。2.2 Python 环境Miniconda 建隔离环境依赖一次锁死用 Python 做机器学习最常翻车的就是环境。装完 python 顺手 pip install 一堆库过两个月发现 numpy 升了大版本xgboost 和 scikit-learn 的版本对不上代码开始报一些莫名其妙的错。这时候才想起来环境隔离已经要花半天排查。我现在的习惯是每个项目建一个独立的 conda 环境python 版本固定用 3.9 或 3.10 这类稳定版别追最新版也别太老。# 创建独立环境指定 python 版本 conda create -n ml_project python3.10 -y # 切换到该项目环境注意终端提示符前面会出现环境名 conda activate ml_project # 安装机器学习全套核心依赖 pip install pandas numpy scikit-learn xgboost shap matplotlib这里有一个很多人会踩的坑打开终端直接 pip install装到了 base 环境里activate 之后 import 却报 No module named。所以安装前先确认终端提示符前面出现了 (ml_project) 字样。装完可以用 pip list 看一眼numpy、pandas、scikit-learn 是否都在这个环境里。依赖管理我一般再加一个 requirements.txt把上面装的包名写进去。想要锁版本就在包名后面加双等号和当前能装到的稳定版号。很多人问 python 安装 numpy 库的方法其实在 conda 环境里就一条 pip install numpy 的事难点从来不在安装命令而在装完不知道装到了哪个环境。注意不要什么都装最新版xgboost 和 scikit-learn 这两个包的大版本变动经常带来接口不兼容锁好版本是给未来的自己留后悔药。2.3 跑通最小脚本确认环境没有暗病环境搭好之后别急着写业务代码先跑一个最小脚本验证整条链路。这个脚本要包含三件事能导入核心库、能读数据、能完成一次最简单的计算。我之前遇到用户反馈代码运行不了远程一看是 Windows 上缺少 VC 运行库导致 msvcp140.dll 找不到报错pandas 和 numpy 一 import 就崩。这种问题不先暴露出来很容易被误判成代码 bug。# verify_env.py环境验证最小脚本 import pandas as pd import numpy as np from sklearn.ensemble import RandomForestClassifier import xgboost as xgb print(pandas:, pd.__version__) print(numpy:, np.__version__) print(xgboost:, xgb.__version__) # 用随机数据做一次最小训练验证 sklearn 和 xgboost 能正常协作 X np.random.rand(200, 5) y (X[:, 0] X[:, 1] 1).astype(int) clf RandomForestClassifier(n_estimators10, random_state42) clf.fit(X, y) print(最小训练完成得分, clf.score(X, y))这段脚本本身没有任何业务逻辑但它的作用很大验证每个核心库都装到了当前环境、版本之间互相兼容、CPU 指令集和运行库没有问题。跑完看到三行版本号和一条训练得分再开始做数据建模后面碰到的报错基本就是代码问题不会再是环境问题。这一步十分钟换来的是一整天不折腾环境。如果遇到 msvcp140.dll 缺失去装对应的 VC Redistributable 运行库即可装完重启终端再跑一遍脚本。3. 数据建模的起点数据处理、规范化与特征工程怎么做有人问“机器学习中的数据处理是什么”说白了就是把原始数据从“人看得懂”变成“模型吃得下”。这个环节占一个数据建模项目一大半工作量却最容易被急着建模的人跳过。跳过数据处理的代价是模型跑出高分换一批数据就崩或者训练集和测试集分布对不上线上完全没法用。下面这套流程是我处理结构化数据的基本套路按顺序走能避免大多数低级错误。3.1 先探查再清洗read_csv 之后的五件事数据到手第一件事永远是看数据长什么样而不是急着建模。我会在 notebook 里跑一段探查代码把数据的类型、缺失、分布一次性看完。import pandas as pd # 读取原始数据Windows 导出的 csv 编码可能是 gbk先尝试 utf-8-sig df pd.read_csv(data/raw_data.csv, encodingutf-8-sig) # 1) 总体规模和每列类型 print(df.shape) print(df.dtypes) # 2) 缺失值数量按列统计 print(df.isnull().sum()[df.isnull().sum() 0]) # 3) 连续特征的分布概况均值、标准差、分位数 print(df.describe().T) # 4) 目标变量分布分类看类别占比回归看偏度 print(df[target].value_counts(normalizeTrue)) # 5) 看一眼重复行数量 print(重复行数:, df.duplicated().sum())read_csv 有两个参数最常用encoding 解决乱码parse_dates 把日期列解析成时间类型后面的特征工程才能做时间差计算。探查阶段不用写复杂逻辑关键是强迫自己把每列的类型和缺失情况过一遍。这一步漏了后面所有模型结果都是地基不稳的房子。我见过有人跳过探查直接训练等模型分数特别高才发现目标列里有个不该存在的“是否违约”字段这就是典型的白费功夫。3.2 缺失值、重复值与异常值三块最常见的绊脚石探查之后进入清洗。清洗不是把所有缺失值删光而是根据业务含义和缺失比例做选择。常见做法是缺失比例超过一半的列直接删除因为信息量已经不够缺失比例较低的列数值型用中位数或均值填充类别型用众数填充重复行直接去重异常值用分位数或业务规则判断。处理顺序也很重要先去重再补缺失最后处理异常顺序反了会导致统计口径混乱。from sklearn.impute import SimpleImputer import numpy as np # 1) 删除缺失超过 50% 的列 df df.dropna(threshlen(df) * 0.5, axis1) # 2) 去重保留第一条 df df.drop_duplicates() # 3) 数值列用中位数填充类别列用众数填充 num_cols df.select_dtypes(include[np.number]).columns cat_cols df.select_dtypes(include[object]).columns df[num_cols] SimpleImputer(strategymedian).fit_transform(df[num_cols])这里有一个新手常犯的错误fit_transform 直接作用在整个 DataFrame 上会把缺失值的统计信息混进整列。如果先填充再切分测试集的分布就已经被训练集“看过”了。在建模流程里正确顺序应该是先切训练集和测试集再在训练集上 fit测试集上 transform否则就是数据泄露测试集的结果会虚高。这也是我后面避坑章里专门要展开的一个点。异常值我会先用四分位距IQR扫一遍规则是超出 Q1-1.5*IQR 或 Q31.5*IQR 的点标记出来再结合业务决定是剔除还是封顶。直接删掉异常点不一定对比如收入字段里高收入群体占比小但价值高一刀切删了反而损失信息。我一般会单独生成一个 is_outlier 列保留标记而不是直接改原数据这样模型训练时可以灵活选择。3.3 数据规范化与编码类别特征不能直接塞进模型结构化数据建模里数据规范化是绕不开的一步。不同特征的单位不一样比如年龄是 0 到 100收入是几千到几十万如果不做处理距离类算法和梯度类算法会把量纲大的特征当成主导特征。常见做法是标准化StandardScaler或者归一化MinMaxScaler。树模型对量纲不敏感但线性模型、逻辑回归、神经网络和距离类模型必须做规范化处理各类建模竞赛里这也几乎是送分题。from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.compose import ColumnTransformer # 定义数值列和类别列按实际数据修改 num_features [age, income, credit_score] cat_features [education, city] # 用 ColumnTransformer 把两类处理拼成一条流水线 preprocessor ColumnTransformer([ (num, StandardScaler(), num_features), (cat, OneHotEncoder(handle_unknownignore), cat_features) ]) # 查看处理后数据形状验证流水线没写错 X_processed preprocessor.fit_transform(df) print(处理后的特征矩阵形状, X_processed.shape)这段代码的关键是 ColumnTransformer它像一条传送带数值列走标准化类别列走独热编码最后拼成一个稀疏矩阵喂给模型。handle_unknownignore 让模型遇到训练集里没见过的类别时不报错这在真实数据里经常出现线上来了一个新城市模型不该因为没见过就崩掉。把数据规范化这些处理写进 Pipeline是避免数据泄露最简单的方法。我后面建模部分的代码会直接复用它这也是从“能跑”走向“能交付”的分水岭。4. 建模与分析从基线模型到 XGBoost 的完整调参路径数据准备好之后进入建模。整个机器学习应用流程走到这一步前面做的所有数据处理都开始产生价值。我习惯把建模拆成三个层次先跑一个最简单的基线模型当参照再上一个更强的主模型结构化数据里常用 XGBoost最后用 SHAP 分析解释模型判断依据。这个顺序能回答三个问题模型能不能用、怎么调到最好、它为什么这样判断。少了任何一步代码都只是跑了个寂寞。4.1 基线模型先行没有参照系就不知道调参有没有用很多初学者拿到数据直接上 XGBoost调了半天参数分数上不去其实可能换一个逻辑回归就已经够用。基线模型的意义是提供一个“最低标准”如果复杂模型连简单模型都打不过说明问题出在特征或数据处理上而不是模型不够强。不管是做天气数据分析、门店选址还是用户行为预测先跑基线再上复杂模型这个顺序都不会错。from sklearn.model_selection import train_test_split, cross_val_score from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier # 划分训练集和测试集分类问题用 stratify 保证类别比例一致 X_train, X_test, y_train, y_test train_test_split( X_processed, df[target], test_size0.2, random_state42, stratifydf[target] ) # 基线模型逻辑回归用交叉验证看稳定得分 baseline LogisticRegression(max_iter1000) scores cross_val_score(baseline, X_train, y_train, cv5, scoringroc_auc) print(逻辑回归 CV AUC, scores.mean()) # 对比模型随机森林 rf RandomForestClassifier(n_estimators200, random_state42) rf_scores cross_val_score(rf, X_train, y_train, cv5, scoringroc_auc) print(随机森林 CV AUC, rf_scores.mean())cross_val_score 的 cv5 把训练集切成五份轮流训练能比单次切分更稳定地反映模型能力。random_state42 是固定种子保证每次跑结果一致这在调参时特别重要。没有固定种子你根本分不清分数的提升来自参数还是来自随机波动。基线模型跑完先记下它的 AUC 或 RMSE后面每一步改动都和这个数字比而不是凭感觉说“好像变好了”。4.2 XGBoost 代码模板结构化数据建模的默认选择如果没有特殊理由结构化数据的主模型我一般直接选 XGBoost。它对特征量纲不敏感自带缺失值处理逻辑支持早停是数据建模与分析里性价比最高的一档。xgboost 代码的难点不在调用而在参数之间互相影响很多人搜到别人贴出的参数就照着抄换数据后完全不对。其实核心参数就那么几个理解了逻辑之后再调就顺了。import xgboost as xgb from sklearn.metrics import roc_auc_score # 实例化 XGBoost 分类器回归任务换成 XGBRegressor 即可 model xgb.XGBClassifier( n_estimators500, # 最大迭代轮数 learning_rate0.05, # 每棵树贡献的学习率越小越稳 max_depth5, # 单棵树最大深度防过拟合 subsample0.8, # 每轮训练采样比例 colsample_bytree0.8, # 每棵树用多少比例的特征 eval_metricauc, early_stopping_rounds30, # 连续 30 轮验证集不提升就停 random_state42 ) # 训练时要给早停准备验证集 model.fit( X_train, y_train, eval_set[(X_test, y_test)], verboseFalse )说几个参数之间的关系max_depth 和 n_estimators一个控制单棵树的复杂度一个控制整体迭代量两者一起增大时模型容易过拟合learning_rate 调低时往往需要更多轮数才能收敛所以早期实验我习惯先固定 learning_rate再调 max_depth最后动采样比例。early_stopping_rounds 是最省心的参数它让模型在验证集指标连续不提升时自动停止避免手动数着轮数试错。训练完再看测试集表现y_pred_prob model.predict_proba(X_test)[:, 1] print(XGBoost 测试集 AUC, roc_auc_score(y_test, y_pred_prob))如果 XGBoost 和基线模型差距不到 0.03我一般会回头查数据处理和特征工程而不是继续堆参数。调参的边际收益是递减的数据质量才是决定模型上限的东西。这个判断标准救过我很多次至少不会在参数上浪费三天。4.3 SHAP 分析给黑匣子模型开一条缝实际项目里最怕的问题不是“模型准确率多少”而是“模型为什么这么判断”。XGBoost 自带的 feature_importances 只能给一个粗略排序SHAP 能给出每个样本上每个特征对预测结果的正负贡献这才是有说服力的分析结果。import shap # 用树模型专用的 Explainer速度快且精度高 explainer shap.TreeExplainer(model) shap_values explainer.shap_values(X_test) # 特征重要性排序图 shap.summary_plot(shap_values, X_test, plot_typebar)summary_plot 的横坐标是 SHAP 值的绝对值大小越大表示贡献越大。色带图里红蓝两个方向分别代表特征值高低对预测的不同影响比如“收入越高模型越倾向于判定为优质客户”这种结论在 SHAP 图里一眼就能看出来。报告中放一张 SHAP 图比贴十行 print 的准确率有说服力得多。如果还想看单个特征怎么影响结果可以加画一行 shap.dependence_plot(income, shap_values, X_test)看它和其他特征的交互关系。分析阶段多花半小时写报告时能少熬两个晚上。5. 避坑排查机器学习代码最常见的五个翻车点前四章把流程走完代码能跑不代表没有隐患。我在帮人排查项目时发现数据建模与分析里翻车最频繁的往往不是算法本身而是数据处理和工程细节。下面五条是我遇到频率最高的按现象、原因、解决三段来写方便你对号入座。5.1 读取 csv 报 UnicodeDecodeError现象pd.read_csv(xxx.csv) 一跑就报 UnicodeDecodeError或者读出来中文全是乱码再往下走 get_dummies 里的中文列名也变成一串英文字母和数字。原因文件本身的编码和 read_csv 默认的 utf-8 不一致。Windows 上用 Excel 导出的 csv 常见是 gbk 或 gb18030 编码还有项目路径带了中文某些库在文件读取时表现不稳定。我一般拿到外部数据后第一件事就是确认编码不然后面每一步都踩在沙子上。# 方案一按文件实际编码读取 pd.read_csv(data/xxx.csv, encodinggbk) # 方案二统一转码后读取utf-8-sig 会去掉开头的 BOM 头 pd.read_csv(data/xxx.csv, encodingutf-8-sig)另外项目中所有路径我坚持用相对路径不要写 C:/Users/张三/Desktop 这种带中文和空格的绝对路径省掉一串兼容性麻烦。编码问题看着小但它会污染后面所有特征列名排查起来非常费劲。5.2 数据泄露清洗和规范化时把目标列一起处理了现象训练时模型 AUC 高达 0.98一上测试集就跌到 0.7或者换成新数据完全不能用。多数人这时候会怀疑模型参数没调好其实问题出在数据预处理。原因最常见的是先对整个 DataFrame 做 StandardScaler.fit_transform再用切分后的数据训练。scaler 在 fit 时偷看了测试集的统计量等于把测试集的信息泄露给了训练过程。还有人做缺失值填充时用整列的均值去填目标和特徵数据混在一起处理测试集的痕迹早就混进训练里了。解决严格三步走先 train_test_split再在训练集上 fit 预处理器的参数最后用训练集的参数 transform 测试集。直接用 sklearn 的 Pipeline 把预处理和模型串起来是最不容易出错的方式。from sklearn.pipeline import Pipeline pipeline Pipeline([ (preprocess, preprocessor), # 前面定义好的 ColumnTransformer (model, xgb.XGBClassifier(random_state42)) ]) pipeline.fit(X_train, y_train)Pipeline 的好处是 fit 和 predict 自动用同一套预处理逻辑不会出现训练和预测时数据处理不一致的问题。这条解决了模型的测试集分数才真正可信。5.3 matplotlib 中文乱码、横坐标太密集现象图是画出来了但标题和图例全是方块或者日期坐标轴挤成一团黑线完全看不出趋势。跑数据的人经常到这一步才停下来说“图没法看”然后开始搜 python 画图横坐标太密集怎么办。原因matplotlib 默认字体里没有中文字体它按英文字体处理中文自然渲染成方块横坐标刻度太多时 matplotlib 不会自动抽稀几十个日期标签叠一起就是一团。写分析脚本时忽略这两个问题等到交付报告时才想起来返工。解决在画图脚本开头设置中文字体和负数显示再用 plt.xticks(rotation45) 或 MaxNLocator 控制刻度密度。import matplotlib.pyplot as plt # 全局配置中文字体Windows 常用 SimHeimacOS 可用 Arial Unicode MS plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False # 横坐标标签旋转 45 度避免挤在一起 plt.xticks(rotation45)如果字体配置不生效常见原因是 matplotlib 缓存了旧字体配置删掉用户目录下的 matplotlib 缓存目录再重启即可。图是给人看的画不清楚等于没画。5.4 环境装错No module named xgboost现象pip install xgboost 明明成功了运行代码却报 ModuleNotFoundError: No module named xgboost。同样的还有 pandas、sklearn 版本对不上训练时报 n_estimators 参数不识别。原因pip 装到了 base 环境而当前项目用的是另一个 conda 环境或者当前目录下有个同名 py 文件把模块名遮蔽了。这类问题跟代码逻辑无关所以排查起来最气人。还有人是 pip 和 conda 混着用把同一个包装了两份版本互相覆盖。解决先确认当前终端前面有项目环境名前缀再用 python -m pip install 而不是裸 pip install保证装到当前 python 解释器所在环境。装完用 pip list 核对再不行就用 python -c import xgboost; print(xgboost.version) 验证。这套组合拳能解决九成环境问题。5.5 训练时内存被吃满现象数据量一大训练过程报 MemoryError或者电脑风扇狂转进程被系统杀掉。重新启动后又从头开始一整天都在做重复劳动。原因pandas 把所有列默认读成 float64 或 object内存翻倍消耗OneHotEncoder 对高基数类别特征展开成几万列XGBoost 的 n_jobs 参数开满全部核内存随之飙升。这是典型的“能跑和能上线之间差一个工程优化”。解决读取时用 dtype 指定列类型类别变量用 category 类型对高基数类别用频率编码或 embedding 代替独热训练参数里限制 n_jobs 和 tree_method。# 读取时压缩数据类型bool 转 category纯数值列按需转 int32 df pd.read_csv(data/xxx.csv, dtype{category_col: category}) # xgboost 训练时控制资源 xgb.XGBClassifier(n_jobs4, tree_methodhist)tree_methodhist 用直方图近似内存占用能降不少训练速度快精度损失一般很小是我在大数据量项目里的标配。先跑通小数据再逐步加大不要一上来就拿全量硬怼。6. 进阶技巧把代码模板化、持久化并验证可复现前面的代码能跑通一个项目但算不上“全套”。真正值钱的是把它变成自己的模板下一次拿到新数据改配置文件和少量代码就能开工。这里说三个我一直在用的习惯。第一个是参数配置化。把 n_estimators、max_depth、learning_rate 这些经常调的数抽到 config.py 文件里训练脚本只负责读参数不写死数值。这样每次实验改一个文件跑完留下记录别人接手也不用翻遍代码找参数。第二个是模型持久化。训练一次模型要花不少时间下次想复用直接加载不用重新训练。import joblib # 训练完成后保存模型包含预处理和建模整条流水线 joblib.dump(pipeline, models/pipeline_2024.pkl) # 新数据进来时直接加载用同一套逻辑做预测 loaded_pipeline joblib.load(models/pipeline_2024.pkl) y_pred loaded_pipeline.predict_proba(new_data)[:, 1]保存整个 pipeline 而不是只保存模型是关键中的关键。不然预测时还得重新写一遍数据处理逻辑少一个步骤结果就不一样。第三个习惯是固定随机种子。模型训练、数据切分、特征采样都要固定 random_state否则每次跑出来的指标都有波动你自己都分不清改动到底有没有用。验证方法也简单把代码从头到尾重跑一遍两次结果完全一致才算可复现。我现在每接一个数据建模任务第一件事永远是把 config.py 建好、把种子固定然后在数据探查上花一小时。这个习惯救过我很多次让我在交付前不会被突如其来的“上次分数不是这样啊”问倒。希望帮到你。本文还有配套的精品资源点击获取