Python机器学习建模实战:GBDT、GAM、CART、BP与DNN训练代码全解析

发布时间:2026/10/12 23:06:42
Python机器学习建模实战:GBDT、GAM、CART、BP与DNN训练代码全解析 简介面向机器学习学习者的完整代码与数据配套资源聚焦数据建模与分析中的常用模型涵盖广义可加模型GAM、梯度提升决策树GBDT、决策树CART、BP神经网络及深度学习DNN每个模型均匹配独立数据集并保留完整训练记录便于对照理解算法原理与实际调用方式。压缩包共184个文件以117个ipynb笔记为主搭配35个csv数据文件、txt说明、少量excel原始表与可视化图片整包约304.19MB模块化结构适合按需查阅或系统训练。目前已有110人学习下载对需要将机器学习理论落地为可运行代码的开发者来说这套资料既能提供从数据准备到模型评估的完整流程参考也为不同模型在同类数据上的效果对比提供了直接样例。1. 拿这套 Python 机器学习代码做数据建模先看清数据集和模型匹配关系这套压缩包里的内容本质上是一批“一模型一数据”的配套训练代码覆盖了机器学习建模链路里最常用的五个模型广义可加模型 GAM、梯度提升决策树 GBDT、分类回归树 CART、BP 神经网络和深度神经网络 DNN。每个代码文件都对应一份独立数据集比如浏览记录.csv、广告.csv、用户.csv、叶子形状.csv还有一批以d2p01F.csv、d2p15F.csv这类编号命名的数据文件。这种组织方式和 Kaggle 上常见的“一个 notebook 配一份数据”的做法一致主要是让每个模型的训练记录真实可复现而不是在通用数据集上硬套。做数据建模的人拿到这套资源的第一个有效动作不是打开代码跑一遍而是先确认“每份数据长什么样、和哪个模型匹配”。文件里这些 CSV 的体积和字段结构差异很大有的适合做回归有的适合做分类或排序。尤其对正在学习机器学习的新手来说直接跑通代码能建立完整流程感对有经验的分析师来说最值钱的则是那些已经调好参数的训练记录——你可以直接对照自己的业务数据看同样的模型在你的特征条件下会差多少。这套代码值得下载的核心理由是把“从数据预处理到模型评估”的完整链路都留了记录而不只是给个孤零零的模型脚本。2. GBDT 与 GAM 训练代码两个高解释性模型的实现差异与调参要点2.1 GBDT 代码里的训练流程拆解GBDT 是这套资源里最值得细看的集成模型。它通过不断拟合前一棵树的负梯度残差来逐步逼近真实值训练记录里保留了每一轮迭代的损失下降曲线。打开GBDT对应的 Python 脚本默认入口通常长这样import pandas as pd from sklearn.model_selection import train_test_split from sklearn.ensemble import GradientBoostingRegressor from sklearn.metrics import mean_squared_error df pd.read_csv(d2p01F.csv) 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 ) model GradientBoostingRegressor( n_estimators200, learning_rate0.08, max_depth3, subsample0.8, random_state42 ) model.fit(X_train, y_train) y_pred model.predict(X_test) print(RMSE:, mean_squared_error(y_test, y_pred) ** 0.5)这段代码里真正影响训练记录的参数是learning_rate和n_estimators的组合。learning_rate是每一步的收缩系数值越小每一步对残差的修正越保守就需要更多的树来补偿max_depth3在多数表格数据里是合理的起点树过深会放大方差过浅则欠拟合。subsample0.8是随机采样比例它能引入随机性降低过拟合风险。训练记录里如果看到损失函数曲线在后期趋于平缓但验证集误差不降反升说明树的数量已经超出最佳点。最好用早停机制GradientBoostingRegressor本身不直接支持早停但可以用GradientBoostingRegressor配合validation_fraction参数来判断是否提前收敛。2.2 GAM 建模用 pyGAM 做非线性平滑项和 GBDT 不同GAM 的价值在于把“特征与目标之间的关系”显式建模为多个平滑函数的叠加而不是生成一堆不可解释的分裂规则。资源里的 GAM 训练记录一般配合pyGAM或statsmodels的GAM接口。核心代码示例from pygam import LinearGAM, s import pandas as pd df pd.read_csv(浏览记录.csv) X df[[浏览时长, 页面深度, 跳出率]].values y df[是否转化].values gam LinearGAM(s(0) s(1) s(2)) gam.gridsearch(X, y, lamnp.logspace(-3, 3, 10))这里s(0) s(1) s(2)分别对三个特征施加平滑样条项gridsearch会用交叉验证自动搜索最优的惩罚系数lam。lam控制平滑程度——值越大曲线越平滑越小越弯曲。训练记录通常会输出每个特征项的p-value和有效自由度看它们就能判断哪些特征被平滑后仍然显著、哪些基本是噪声。GAM 跟 GBDT 在业务场景上最好互补使用需要向业务方解释“年龄每增加一岁转化率下降多少”时用 GAM单纯追求预测精度时用 GBDT。2.3 GBDT 与 GAM 的边界与适用场景对照这两类模型在数据规模、特征维度和解释性需求上的取舍非常明确。GBDT 能自动处理特征交互和非线性关系对缺失值也不太敏感但需要较多数据来支撑每棵树的训练在稀疏高维特征上容易过拟合。GAM 在数据量不大的场景下表现稳定但无法自动发现特征间的交互——需要手动添加交互项或张量积项。选模型时看业务需求和数据条件而不是一味追求某一类的性能指标。对比维度GBDTGAM解释性通过特征重要性近似解释每个特征的效应函数可直接绘图非线性处理自动拟合依赖平滑项设计特征交互自动学习需显式构建交互项数据量要求较大中小样本即能稳定收敛典型应用排名、回归、分类风险因子分析、营销响应模型3. CART 决策树与 BP 神经网络代码从树结构到反向传播的建模链路3.1 CART 建模分裂逻辑与剪枝策略CART 模型的训练记录展示了从数据加载到剪枝的完整过程。决策树分裂时分类树用基尼系数最小化选择分裂点回归树用均方误差最小化。代码示例from sklearn.tree import DecisionTreeClassifier, export_text import pandas as pd df pd.read_csv(广告.csv) X df.drop(columns[点击]) y df[点击] clf DecisionTreeClassifier( criteriongini, max_depth5, min_samples_split10, min_samples_leaf5, ccp_alpha0.01 ) clf.fit(X, y) print(export_text(clf, feature_nameslist(X.columns)))min_samples_split10表示节点分裂要求至少 10 个样本min_samples_leaf5限制叶子节点至少 5 个样本这两个参数对树结构的约束比max_depth更直接。ccp_alpha0.01是代价复杂度剪枝参数值越大剪枝越激进树越短。训练记录里应该能看到剪枝前后的验证集精度对比——如果剪枝后精度下降不超过一个百分点说明原来的树确实过拟合了。CART 模型在这个资源里的定位是教学型 baseline重点看树的深度和叶子节点数别急着上复杂集成。对初学者来说先用export_text把树结构导出来自己读一遍比看任何指标都有帮助。3.2 BP 神经网络手写反向传播与 sklearn 封装两种路线BP 神经网络的训练记录一般有两种代码形态一种是纯 numpy 手写多层感知机并自己实现反向传播另一种是使用sklearn.neural_network.MLPRegressor。手写版本示例import numpy as np def sigmoid(x): return 1 / (1 np.exp(-x)) np.random.seed(42) X np.random.randn(100, 3) y (X[:, 0] 2 * X[:, 1] - X[:, 2] 0).astype(float) w1 np.random.randn(3, 4) * 0.1 w2 np.random.randn(4, 1) * 0.1 lr 0.1 for epoch in range(500): z1 X w1 a1 sigmoid(z1) z2 a1 w2 a2 sigmoid(z2) loss np.mean((a2.ravel() - y) ** 2) dz2 (a2.ravel() - y).reshape(-1, 1) * (a2 * (1 - a2)) dw2 a1.T dz2 dz1 (dz2 w2.T) * (a1 * (1 - a1)) dw1 X.T dz1 w2 - lr * dw2 w1 - lr * dw1 if epoch % 100 0: print(fepoch {epoch}, loss {loss:.4f})这段代码把 BP 网络的核心逻辑压缩在了 25 行以内。w1和w2的初始化尺度为 0.1避免神经元饱和lr0.1在这个小规模数据集上能稳定收敛。如果发现 loss 震荡或收敛缓慢优先调小学习率或增加隐层维度。手写版本虽然性能不敌框架实现但能让你彻底理解“误差逆传播”到底在传播什么。3.3 BP 和 CART 在本资源数据上的训练配合逻辑浏览记录和广告数据一般维度不高、样本量中等BP 能拟合非线性关系CART 则提供一个可解释的分裂规则。实际做训练记录分析时我通常会把两份代码连跑先用 CART 得到特征重要性排序筛选出前几个核心特征再把这些特征送进 BP 做回归或分类。这种串联方式能减少 BP 网络的输入维度同时也让训练时间大幅下降。4. DNN 深度学习代码实战从数据预处理到模型保存的完整流程4.1 数据预处理与训练集构造DNN 代码一般对应d2p15F.csv这类编号数据特征是数值型与类别型混合。训练记录里第一步是构造数据管道import pandas as pd import numpy as np from sklearn.preprocessing import StandardScaler, LabelEncoder df pd.read_csv(d2p15F.csv) cat_cols [类别, 渠道] # 示例列名按实际数据调整 num_cols [c for c in df.columns if c not in cat_cols [target]] for col in cat_cols: df[col] LabelEncoder().fit_transform(df[col].astype(str)) scaler StandardScaler() X_num scaler.fit_transform(df[num_cols]) X np.hstack([X_num, df[cat_cols].values]) y df[target].valuesLabelEncoder把类别转为整数编码StandardScaler把数值列压缩到零均值单位方差这一步是神经网络收敛的硬前提。对类别特征也可以用 one-hot 编码但如果类别取值超过几十个one-hot 会让输入维度骤增embedding 是更优选择。4.2 用 PyTorch 构建 DNN 并训练资源里的 DNN 代码有 TensorFlow 和 PyTorch 两个版本的可能用 PyTorch 的话核心训练循环必须自己写可控性更好import torch import torch.nn as nn import torch.optim as optim class DNN(nn.Module): def __init__(self, input_dim): super().__init__() self.net nn.Sequential( nn.Linear(input_dim, 64), nn.ReLU(), nn.Dropout(0.2), nn.Linear(64, 32), nn.ReLU(), nn.Linear(32, 1) ) def forward(self, x): return self.net(x) model DNN(X.shape[1]) optimizer optim.Adam(model.parameters(), lr0.001) loss_fn nn.MSELoss() X_t torch.tensor(X, dtypetorch.float32) y_t torch.tensor(y, dtypetorch.float32).view(-1, 1) for epoch in range(300): model.train() optimizer.zero_grad() pred model(X_t) loss loss_fn(pred, y_t) loss.backward() optimizer.step() if epoch % 50 0: print(fepoch {epoch}, loss {loss.item():.4f})这里Dropout(0.2)是 DNN 防止过拟合的关键设计训练时随机丢弃 20% 的神经元迫使网络不依赖单一通路Adam优化器默认学习率 0.001对全连接网络是安全起点。如果你在训练记录里看到 loss 收敛后验证集误差反而升高第一反应不是调结构而是加 dropout 或者降学习率。4.3 DNN 训练完成后的模型保存与加载训练结束后的一个常见断点是把模型结构和权重一并保存方便后续部署或二次训练torch.save({ model_state_dict: model.state_dict(), input_dim: X.shape[1], scaler: scaler }, dnn_model.pth) # 加载时 checkpoint torch.load(dnn_model.pth) model DNN(checkpoint[input_dim]) model.load_state_dict(checkpoint[model_state_dict])如果你在训练记录里看到 loss 收敛后验证集误差反而升高第一反应不是调结构而是加 dropout 或者降学习率。在 Python 程序里用argparse解析命令行参数时参数2在名称前是标准写法不会因为排序而改变绑定的值。模型保存时保留input_dim和scaler就避免了重新加载时“维度对不上”和“数据没归一化”两类问题。5. 训练记录避坑指南数据对齐、过拟合与框架版本三个高频翻车点5.1 数据集与代码不匹配导致 KeyError现象代码运行时直接报KeyError: target或ValueError: X has 10 features, but DecisionTreeClassifier is expecting 12 features。解决每个 CSV 的列名和对应代码并不完全一致。原因这套资源里每个模型都配了独立数据文件但数据集的字段命名规则不统一——有的数据用target作为目标列名有的用label有的甚至直接是最后一列没有表头。代码里写死了df[target]换一个数据集就崩。解决写一个通用适配层先把列名统一再进模型import pandas as pd def load_dataset(path, target_hinttarget): df pd.read_csv(path) if target_hint in df.columns: y df[target_hint] X df.drop(columns[target_hint]) else: y df.iloc[:, -1] X df.iloc[:, :-1] return X, y如果输入的 CSV 没有目标列就把最后一列视作目标前 m-1 列作为特征。load_dataset的主要价值是让代码在不同数据集间切换时不触礁避免频繁修改列名。5.2 过拟合被误判为模型性能好现象训练集 RMSE 非常低测试集误差高出数倍。在 BP 和 DNN 训练记录里特别常见。原因资源里的部分代码刻意保留了较大网络容量同时数据量只有几千行。如果参数设置里没有正则化项或 dropout网络会直接把训练样本“背下来”。解决优先加入正则化约束然后重跑训练记录from sklearn.neural_network import MLPRegressor model MLPRegressor( hidden_layer_sizes(64, 32), alpha0.01, max_iter800, early_stoppingTrue, n_iter_no_change20 )alpha0.01是 L2 正则化系数它会让大权重受到惩罚从而限制网络复杂度。early_stoppingTrue配合n_iter_no_change20意味着验证误差连续 20 轮不下降就停止训练——这两个参数是神经网络建模里最经常拯救结果的组合。5.3 深度学习框架版本不兼容导致代码无法运行现象按照训练记录执行import torch正常但跑到torch.load(dnn_model.pth)报错或者optimizer.step()之后 loss 是nan。原因PyTorch 不同版本之间torch.load的默认行为有差异高版本默认weights_onlyTrue加载包含scaler这类自定义对象的 checkpoint 会直接失败。另一个常见原因是 PyTorch 和 CUDA 版本不匹配导致张量计算产生nan。解决加载时显式指定weights_onlyFalse并在训练前检查 CUDA 可用性torch.load(dnn_model.pth, weights_onlyFalse) assert torch.cuda.is_available() or torch.backends.mkl.is_available(), \ CPU training will be slow; consider reducing layer size.5.4 数据泄漏预处理在划分前完成现象验证集精度虚高但上线后效果断崖式下降。原因代码把StandardScaler和LabelEncoder在train_test_split之前就 fit 到了全量数据上验证集的信息在训练阶段就已经被模型偷看到了。这在 DNN 和 BP 的训练记录里都是隐蔽性很高的错误。解决先划分再预处理scaler 只用训练集拟合from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test)scaler.fit_transform(X_train)只计算训练集的均值和方差X_test_scaled用同一参数做变换而不再 fit这才是正确的预处理顺序。5.5 训练记录与代码版本错位现象你照着博客里的参数抄了一份代码但结果和训练记录对不上误差差了一倍。原因d2p01F.csv和d2p02F.csv的数据分布不同同一个模型在两组数据上不可能得到相同结果。这个资源的设计本来就是“一模型一数据”如果只拿某一份数据套另一份数据的参数性能和收敛速度都会受影响。解决先确认代码头部注释里写的数据集文件名再确定训练参数。如果代码没有注释用.shape和.describe()对数据做初步体检看维度、均值、缺失率判断当前数据是哪份训练记录的对应项。6. 特征重要性与误差曲线可视化把训练记录真正用起来训练完成后最值得做的事未必是调参而是把训练记录里埋着的信息可视化出来。这能帮你确认模型学到的是规律还是噪声也能让你向业务方讲清楚“为什么这个模型给出了这样的预测”。对 GBDT 和 CART 来说特征是核心产出对 BP 和 DNN 来说损失曲线和预测-真实散点图是比较核心的诊断工具。首先用 GBDT 的属性直接输出特征重要性再配合 CART 的树结构做交叉验证import matplotlib.pyplot as plt import pandas as pd from sklearn.ensemble import GradientBoostingRegressor df pd.read_csv(用户.csv) X df.drop(columns[消费金额]) y df[消费金额] model GradientBoostingRegressor( n_estimators150, max_depth3, learning_rate0.05 ) model.fit(X, y) importance pd.Series(model.feature_importances_, indexX.columns) importance.sort_values(ascendingTrue).plot.barh(figsize(8, 5)) plt.title(GBDT Feature Importance) plt.tight_layout() plt.savefig(feature_importance.png, dpi150)feature_importances_的值代表每个特征在全部树中被选为分裂特征的加权次数占比所有特征的和为 1。barh绘制横向柱状图是为了让特征名称完整显示dpi150的导出质量够公众号和汇报 PPT 使用。如果某个特征重要性接近 0但在 CART 的树结构里它频繁出现在深层节点说明这个特征只对少数样本有区分度业务上可以降权。再看损失曲线这是判断 GBDT 是否欠拟合或过拟合的直接证据from sklearn.model_selection import validation_curve param_range [50, 100, 150, 200, 300] train_scores, test_scores validation_curve( GradientBoostingRegressor(learning_rate0.05, max_depth3), X, y, param_namen_estimators, param_rangeparam_range, cv5, scoringneg_mean_squared_error )validation_curve对每组n_estimators做 5 折交叉验证返回训练集和验证集的得分数组。画出两条曲线后如果验证集得分在n_estimators150之后不再提升而训练集得分继续上升这就是过拟合的明确信号说明该在这个点截断。训练记录里的损失值都是浮点误差直接用图片对比更直观。对 BP 和 DNN把预测值跟真实值画散点图能快速发现系统性偏差——如果散点整体偏移对角线说明模型有偏置如果散点呈现出明显的弧形说明网络容量不够需要增加神经元数或层数。数值预测模型很难想象。最后再说一个习惯从那以后我再拿到任何一套训练代码第一件事永远是跑plt.figure()画出误差曲线和特征排序然后才去看参数配置表而不是先跑模型后看输出。一套代码包里数据再多、模型再全没有可视化的辅助判断你依然是在黑匣子里调整参数。把每条训练记录的关键曲线存成 PNG和模型文件放在同一个目录下能让这份资源从“能跑的代码”变成“能复用的经验库”。希望这些拆解对你有帮助。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询