简介:基于XGBoost的数据回归预测Python代码,面向机器学习初学者与应用型开发者,以波士顿房价为实验对象,演示从Excel加载数据、划分训练集与测试集、训练XGBoost回归模型并评估的完整流程。压缩包共5个文件,包含主脚本(.py)、训练与测试数据集(.xlsx)、结果展示图(.png)以及说明文档(.md),包体仅191KB,轻量易用。目前已有4293人学习/下载,是快速上手梯度提升回归的实用参考。脚本运行后将生成训练集与测试集的真实值-预测值散点图,并绘制测试集逐样本对比折线图,同时输出均方根误差(RMSE)作为量化指标。借助附带数据集与README说明,读者可一键复现实验,也可替换为自己的Excel数据进行迁移练习,适合课设、论文复现或入门机器学习项目时参考。
1. 这份XGBoost回归代码:从Excel到散点图折线图,一次跑通的完整闭环
很多人以为XGBoost是打比赛、做分类用的,其实回归预测才是它最见功力的场景。你手里如果有一批历史数据存在Excel里,想预测房价、销量、温度这种连续值,最常见的做法就是pandas读表、XGBoost训练、再画图看拟合效果。这份代码包做的事情正好就是这个闭环:boston_housing_train_data.xlsx和boston_housing_test_data.xlsx已经把波士顿房价数据拆好了训练集和测试集,xgboost_regression.py加载后直接训练XGBoost回归模型,最终输出三张图——训练集散点图、测试集散点图、测试集折线图,外加一个RMSE均方根误差数值。
适合谁?刚把sklearn基础跑通、想上手XGBoost的Python数据分析新手最合适;已经写过机器学习代码但懒得从零搭数据管线的熟手,也能直接拿这个脚本当模板改。下面我从数据加载、模型参数、可视化细节到踩坑记录,把这份代码整个拆开讲透。
2. 数据准备与建模选型:为什么是XGBoost,Excel怎么读才对
2.1 波士顿房价数据集:13个特征预测一个连续值
波士顿房价是回归任务里的经典数据集,506个样本,每个样本包含CRIM(犯罪率)、RM(房间数)、AGE(房龄)等13个特征,目标值是MEDV(自住房屋中位数价格)。整套数据本质上是小样本表格数据,非常契合树模型的发挥区间。
这份项目里数据不是从sklearn内置接口加载的,而是预先拆成了两个Excel文件。训练集和测试集已经按行分好,这意味着你不需要自己再调train_test_split,但代价是必须保证两个文件的特征列顺序完全一致。我第一次拿到这类拆分好的文件时习惯先打印两个表的shape,确认特征列数相同,再干活。
import pandas as pd train_df = pd.read_excel("boston_housing_train_data.xlsx") test_df = pd.read_excel("boston_housing_test_data.xlsx") print("训练集 shape:", train_df.shape) print("测试集 shape:", test_df.shape) print("训练集列名:", train_df.columns.tolist()) print("测试集列名:", test_df.columns.tolist()) print("训练集空值统计:\n", train_df.isnull().sum())逻辑说明:先看形状和列名,能第一时间发现文件拆错了、列对不齐这类基础问题。空值统计这一步不能省,XGBoost虽然自带缺失值处理,但如果空值比例异常,训练出来的模型会被带偏。参数说明:read_excel不指定sheet_name时默认读第一个sheet;如果文件里有多个sheet,要写成pd.read_excel("xxx.xlsx", sheet_name="Sheet1")。
2.2 XGBoost回归原理:为什么它对中小表格数据这么能打
XGBoost全称是Extreme Gradient Boosting,核心思想是不断训练决策树,让后一棵树拟合前一棵树的残差。它和普通梯度提升树的关键区别在于目标函数里加了正则化项,并且对损失函数做了二阶泰勒展开,收敛更快、泛化更稳。
对回归任务来说,XGBoost默认的损失函数是平方误差回归损失。它有个很实用的特性:不需要像线性回归那样做特征标准化,因为树模型是分桶分裂的,特征尺度不影响分裂点。对这份波士顿房价数据,我直接用原始Excel字段就能训练,省掉了一大段特征工程代码。
import xgboost as xgb from xgboost import XGBRegressor X_train = train_df.drop(columns=["MEDV"]) y_train = train_df["MEDV"] X_test = test_df.drop(columns=["MEDV"]) y_test = test_df["MEDV"] model = XGBRegressor( n_estimators=200, max_depth=4, learning_rate=0.1, subsample=0.8, colsample_bytree=0.8, random_state=42 ) model.fit(X_train, y_train)逻辑说明:这里把MEDV列单独拎出来当标签,其余13列全部作为特征。XGBRegressor是XGBoost封装的回归接口,不需要手动把数据转成DMatrix格式,适合快速验证。参数说明:n_estimators=200是树的数量,波士顿数据只有几百个样本,200棵足够;max_depth=4限制树的深度防止过拟合,千万不要一上来就设成10;subsample和colsample_bytree都是0.8,意思是每棵树随机用80%的样本和80%的特征,相当于自带bagging效果。
3. 模型训练与核心评估:RMSE怎么算,两组散点图怎么画
3.1 训练集和测试集的RMSE:先看数值,再看图
训练完成后的第一件事就是算误差。RMSE(均方根误差)是回归任务最常用的评估指标,它把预测值和真实值的差平方后取平均再开方,单位跟房价本身一致,能直观反映平均偏差。
import numpy as np from sklearn.metrics import mean_squared_error y_train_pred = model.predict(X_train) y_test_pred = model.predict(X_test) rmse_train = np.sqrt(mean_squared_error(y_train, y_train_pred)) rmse_test = np.sqrt(mean_squared_error(y_test, y_test_pred)) print(f"训练集 RMSE: {rmse_train:.4f}") print(f"测试集 RMSE: {rmse_test:.4f}")逻辑说明:先把训练集和测试集的预测值都算出来,再分别和真实标签计算RMSE。这里有个值得注意的点——如果训练集RMSE远低于测试集RMSE,比如训练集1.2、测试集4.8,说明模型过拟合了,后面调参重点是减小max_depth、增大min_child_weight。参数说明:mean_squared_error计算的是均方误差,开根号后才叫RMSE;保留四位小数足够看出差异,实际汇报时用两位小数即可。
3.2 训练集散点图和测试集散点图:一张图看出过拟合
散点图是回归预测最直观的体检报告:横轴是真实值,纵轴是预测值,所有点贴在对角线y=x上就是完美预测。
import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = ["SimHei"] plt.rcParams["axes.unicode_minus"] = False fig, axes = plt.subplots(1, 2, figsize=(12, 5)) axes[0].scatter(y_train, y_train_pred, alpha=0.6, edgecolors="k", linewidths=0.3) axes[0].plot([y_train.min(), y_train.max()], [y_train.min(), y_train.max()], "r--", lw=1.5) axes[0].set_xlabel("真实值") axes[0].set_ylabel("预测值") axes[0].set_title(f"训练集散点图 (RMSE={rmse_train:.2f})") axes[0].grid(alpha=0.3) axes[1].scatter(y_test, y_test_pred, alpha=0.6, edgecolors="k", linewidths=0.3) axes[1].plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], "r--", lw=1.5) axes[1].set_xlabel("真实值") axes[1].set_ylabel("预测值") axes[1].set_title(f"测试集散点图 (RMSE={rmse_test:.2f})") axes[1].grid(alpha=0.3) plt.tight_layout() plt.savefig("Figure_1.png", dpi=150) plt.show()逻辑说明:两张子图横向并排,左边训练集、右边测试集,一眼就能对比。红色虚线是理想预测线,点散得越窄、越贴线,说明模型表现越好。alpha=0.6控制点的透明度,数据点密集时能避免黑乎乎一大片。参数说明:edgecolors="k"给散点加了黑色描边,这在点很多时能显著提升区分度;grid(alpha=0.3)把网格调淡,防止网格线抢了数据点的视觉权重;dpi=150保证保存的图放大不糊。
提示:如果两张图的点都明显偏离对角线,优先检查特征是否包含了和标签同义的数据列。
4. 折线图逐样本对比:把平均误差还原成「哪里差、差多少」
4.1 测试集折线图画法:真实值序列和预测值序列叠一起
散点图告诉我们整体拟合程度,但看不出模型到底在哪些样本上翻车。折线图把测试集按样本序号排开,真实值一条线、预测值一条线,两条线贴得越近越好。
num_samples = len(y_test) x_idx = np.arange(num_samples) plt.figure(figsize=(14, 5)) plt.plot(x_idx, y_test.values, "b-o", markersize=3, label="真实值") plt.plot(x_idx, y_test_pred, "r-o", markersize=3, label="预测值") plt.xlabel("测试集样本序号") plt.ylabel("MEDV 房价") plt.title(f"测试集真实值与预测值对比 (RMSE={rmse_test:.2f})") plt.legend() plt.grid(alpha=0.3) plt.tight_layout() plt.show()逻辑说明:蓝色线是真实房价,红色线是模型预测值,横轴是测试集的行序号。这种图的价值在于能看到局部偏差——比如某个区间两条线明显分开,说明模型对那个价格段的样本学习得不够。参数说明:"b-o"表示蓝色实线加圆点标记,markersize=3控制圆点大小,样本量大时marker可以去掉改成"b-",避免点太密看不清。
4.2 折线图的三种典型「病相」与因果
折线图不是画完就完事的,得会读。我一般看三个地方:整体贴合度、峰谷是否错位、有没有系统性偏移。
第一种情况,预测线整体比真实线低一截,大概率是特征里漏掉了某个重要驱动因素。第二种情况,真实线冲到高位的时候预测线没跟上,说明模型对高房价段拟合不足,可以适当增加max_depth。第三种情况,预测值波动得比真实值厉害,出现了锯齿状,通常是树数量太少或learning_rate设得太大。
# 找出偏差最大的前 5 个样本 residual = np.abs(y_test.values - y_test_pred) worst_idx = np.argsort(residual)[-5:][::-1] for idx in worst_idx: print(f"样本#{idx}: 真实值={y_test.values[idx]:.2f}, " f"预测值={y_test_pred[idx]:.2f}, 偏差={residual[idx]:.2f}")逻辑说明:计算每个样本预测值和真实值的绝对误差,用argsort排序后取后五个最大偏差样本打印出来。这样能定位到具体是哪些样本拉高了RMSE。如果最差的几个样本都是高房价样本,可以针对性地考虑要不要对目标值做对数变换。
5. 常见问题与避坑:这份代码跑起来可能遇到的四个真实坑
5.1 读Excel直接报错:xlrd版本冲突
现象:pd.read_excel("boston_housing_train_data.xlsx")执行时抛异常,提示xlrd不支持xlsx格式。
原因:xlrd从2.0.0版本开始只支持.xls,不支持.xlsx。如果你用pip install xlrd装到了最新版,哪怕代码写得再对,这一步也会翻车。
解决:用openpyxl引擎。pip install openpyxl之后,把读取代码改成pd.read_excel("xxx.xlsx", engine="openpyxl")。我自己的习惯是直接只用openpyxl,因为新版xlrd基本废了。
5.2 散点图糊成一团黑色,完全看不出趋势
现象:图是出来了,但所有点重叠在一起,看起来像一块黑板。
原因:数据点太密集,默认的scatter设置没有透明度,也没有描边,点与点互相覆盖。
解决:设置透明度alpha=0.5~0.7,加描边edgecolors="k",调整点的大小s=20~50。如果这样还不够,可以把一个子图单独放大看局部区域,或者用hexbin六边形密度图替代散点图。
5.3 RMSE算出来是天文数字(几千上百万)
现象:程序跑通了,图也画了,但RMSE输出大得离谱,完全不像房价尺度。
原因:八成是特征里混进了和标签相关的反推列。比如Excel里同时给了MEDV和某列与MEDV线性相关的数值,模型在训练集上完美拟合,但测试集一换数据就崩;另一种可能是drop的时候列名写错,导致特征矩阵里碰巧还留着MEDV。
解决:打印X_train.columns.tolist(),肉眼检查有没有不该出现的列名。波士顿数据集的标准做法是drop(columns=["MEDV"]),这一行代码写错位置或写错列名,后面全是白干。
5.4 训练集效果好、测试集一塌糊涂
现象:训练集RMSE只有1.8,测试集RMSE飙到6.5,散点图一眼就看出过拟合。
原因:经典的过拟合——树太深、树太多、数据太少。波士顿只有三百多条训练样本,max_depth=10、n_estimators=1000这种配置几乎必然过拟合。
解决:把max_depth降到3~5,learning_rate降到0.05~0.1,然后增加n_estimators配合早停。XGBoost支持early_stopping_rounds,用验证集做早停判断,比手动试参数靠谱得多。
注意:XGBoost的
early_stopping_rounds参数需要配合验证集传入eval_set,不是随便加个数字就能启动的。
6. 往工程化走一步:输出特征重要性和预测结果文件
跑通这份回归代码只是起点,真正要把它用到实际项目里,我一般会再加两步:打印特征重要性、把预测结果导回Excel。
import pandas as pd importance = model.feature_importances_ feat_names = X_train.columns.tolist() feat_imp_df = pd.DataFrame({ "特征": feat_names, "重要性": importance }).sort_values("重要性", ascending=False) print("\n特征重要性 Top5:") print(feat_imp_df.head(5).to_string(index=False)) result_df = pd.DataFrame({ "真实值": y_test.values, "预测值": y_test_pred, "绝对误差": residual }) result_df.to_excel("prediction_result.xlsx", index=False)逻辑说明:feature_importances_是XGBoost模型训练完成后自带的属性,按特征被用于分裂的增益加权统计得出。把这它和特征名拼成DataFrame排序,能快速看出哪些字段对房价预测贡献最大。预测结果导出到Excel则方便给下游业务同事核验。
从那以后我每次跑回归模型,不管任务多急,都强制自己走一遍这个流程:先打印特征重要性,再导出预测文件。一来是逼着自己理解模型、别当黑匣子用,二来是对方万一说“你这个预测不对”,我可以翻出文件逐条对账。XGBoost这份资源的核心价值不是帮你调出完美模型,而是给你一个能稳定复现的基线——后续换数据、换特征、换模型,都能拿它当参照物对比效果。希望帮到你。
本文还有配套的精品资源,点击获取