机器学习实战:LightGBM与XGBoost二手车价格预测源码解析

发布时间:2026/10/13 21:15:43
机器学习实战:LightGBM与XGBoost二手车价格预测源码解析 简介这份资源是面向计算机、人工智能、大数据及数学等相关专业学生的机器学习实战项目包聚焦二手车交易价格预测这一典型回归赛题适合正在做课程设计、期末大作业或毕业设计的学习者参考也可作为入门机器学习建模流程的练手素材。压缩包共16个文件约32.04MB以csv数据集、ipynb代码笔记、xml与iml工程配置、md说明文档及txt依赖清单为主其中csv承载训练与测试样本ipynb分别给出LightGBM与XGBoost两套建模实现md与txt则用于说明项目结构与运行环境。目前已有318人学习下载。读者可从中获得完整的赛题方案包括数据读取与特征处理、两种集成学习模型的训练与调参、预测结果输出与提交流程并附有项目说明帮助理解目录组织与代码逻辑便于在此基础上复现、改进或迁移到其他价格预测场景。1. 二手车价格预测项目从数据到模型一份能跑通的机器学习实战源码二手车定价这件事做过的人都知道有多玄学。同一款车不同城市、不同过户次数、不同排量价格能差出一大截。靠人工经验估价不仅慢而且很难规模化。这份「基于机器学习的二手车交易价格预测算法源码项目说明.zip」就是冲着这个问题来的——它用 LightGBM 和 XGBoost 两套梯度提升框架把二手车交易价格预测做成了一个完整的、可复现的工程项目。资源包里包含训练集、测试集、提交样例、两个 Jupyter Notebook 以及依赖清单结构清晰下载解压后按顺序跑就能出结果。适合正在做机器学习课程设计、期末大作业或毕设的同学也适合想拿一个真实回归任务练手的从业者。它不教你从零推导梯度提升但能让你在真实数据上把「特征工程 → 模型训练 → 预测提交」这条链路完整走一遍。2. 数据与任务拆解先搞清楚预测目标再动手拿到一份机器学习源码最忌讳上来就jupyter notebook一路 ShiftEnter。先花十分钟把数据和任务搞清楚后面能省掉大量返工。2.1 三份 CSV 各是什么字段怎么读资源包里的data目录下有三个核心文件文件名用途说明used_car_train_20200313.csv训练集含标签price用于训练模型used_car_testB_20200421.csv测试集不含price用于生成预测结果used_car_sample_submit.csv提交样例规定提交格式通常是SaleIDprice训练集和测试集的字段结构基本一致常见字段包括SaleID交易唯一标识、name车型编码、regDate注册日期、model车型、brand品牌、bodyType车身类型、fuelType燃油类型、gearbox变速箱、power马力、kilometer里程、notRepairedDamage是否有未修复损伤、regionCode地区编码、seller卖家类型、offerType报价类型、creatDate交易时间以及price价格仅训练集有。这里有个容易翻车的点price在原始数据里往往不是标准正态分布而是明显右偏。如果直接拿来做回归模型会被高价样本带偏。常见做法是先对price做对数变换预测完再指数还原。这一步在 Notebook 里通常会有体现但如果你自己改代码别忘了这个操作。2.2 任务类型与评估指标这是一个典型的有监督回归任务输入是车辆的各种属性输出是一个连续的价格值。评估指标一般是 MAE平均绝对误差或 RMSE均方根误差。MAE 对异常值更鲁棒RMSE 对大误差惩罚更重。这份源码里两个 Notebook 分别用 LightGBM 和 XGBoost 实现你可以对比两者在同一数据上的表现差异。提示如果你的课程设计或毕设要求写实验对比这份源码天然提供了两个模型的对照直接拿来用比从零搭省事得多。2.3 环境准备与依赖安装资源包根目录有requirements.txt先看它写了什么再决定怎么装。常见依赖包括numpy、pandas、scikit-learn、lightgbm、xgboost、matplotlib、seaborn、jupyter。# 创建独立环境避免污染全局包 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 安装依赖 pip install -r requirements.txt # 如果 lightgbm 或 xgboost 安装慢可以换国内镜像源 pip install lightgbm xgboost -i https://pypi.tuna.tsinghua.edu.cn/simple逻辑说明用虚拟环境隔离依赖是基本操作避免不同项目之间版本冲突。requirements.txt里如果没锁版本号建议手动加上lightgbm3.3.0和xgboost1.5.0这类下限防止装到过老版本导致 API 不兼容。参数方面Python 版本建议 3.8 以上LightGBM 和 XGBoost 对 3.7 以下支持越来越差。3. LightGBM 与 XGBoost 双模型实战从特征工程到提交文件这一章是整份源码的核心。两个 Notebook 的结构类似但细节处理上有差异。我按实际跑通的顺序拆一遍。3.1 数据加载与缺失值处理先看数据规模。训练集通常有 15 万条左右测试集 5 万条左右字段 30 个上下。加载时注意read_csv的sep参数有些版本用空格分隔有些用逗号看文件实际内容。import pandas as pd import numpy as np # 加载数据注意编码和分隔符 train pd.read_csv(data/used_car_train_20200313.csv, sep ) test pd.read_csv(data/used_car_testB_20200421.csv, sep ) sample_submit pd.read_csv(data/used_car_sample_submit.csv) print(训练集形状:, train.shape) print(测试集形状:, test.shape) print(提交样例形状:, sample_submit.shape) # 查看缺失值分布 missing train.isnull().sum() missing missing[missing 0].sort_values(ascendingFalse) print(缺失字段及数量:\n, missing)逻辑说明sep 是因为部分二手车数据集用空格分隔而非逗号如果报错就改成sep,。缺失值统计是为了决定填充策略——bodyType、fuelType、gearbox这几个字段通常有缺失常见做法是用众数填充或单独标记为「未知」类别。notRepairedDamage字段里可能有-这种非数值字符需要先替换成NaN再处理。参数方面read_csv的low_memoryFalse可以在字段类型混杂时避免警告但会吃内存15 万条数据问题不大。3.2 特征工程日期拆解与类别编码原始字段里regDate和creatDate是日期字符串直接扔给模型没用。需要拆成年、月、日甚至算出「车龄」这个更有业务含义的特征。# 日期特征拆解 train[regDate] pd.to_datetime(train[regDate], format%Y%m%d, errorscoerce) train[creatDate] pd.to_datetime(train[creatDate], format%Y%m%d, errorscoerce) train[car_age] (train[creatDate] - train[regDate]).dt.days # 测试集同样处理 test[regDate] pd.to_datetime(test[regDate], format%Y%m%d, errorscoerce) test[creatDate] pd.to_datetime(test[creatDate], format%Y%m%d, errorscoerce) test[car_age] (test[creatDate] - test[regDate]).dt.days # 类别特征编码brand、bodyType、fuelType、gearbox 等 from sklearn.preprocessing import LabelEncoder cat_cols [brand, bodyType, fuelType, gearbox, notRepairedDamage] for col in cat_cols: le LabelEncoder() # 合并训练集和测试集一起编码保证类别一致 full_data pd.concat([train[col], test[col]], axis0).astype(str) le.fit(full_data) train[col] le.transform(train[col].astype(str)) test[col] le.transform(test[col].astype(str))逻辑说明car_age用交易日期减注册日期得到车辆使用天数比单独用regDate更有预测价值。LabelEncoder把类别转成整数注意必须把训练集和测试集拼在一起fit否则测试集出现训练集没见过的类别时会报错。这是血泪经验——很多人分开编码结果测试集里有个别品牌训练集没有直接崩掉。参数方面errorscoerce让无法解析的日期变成NaT后续可以填充或删除。car_age如果出现负值交易日期早于注册日期说明数据有问题可以截断到 0 或直接剔除。3.3 LightGBM 模型训练与调参LightGBM 的优势是训练快、内存占用低、对类别特征支持好。源码里的1--LightGBM.ipynb通常会用lgb.Dataset封装数据然后lgb.train训练。import lightgbm as lgb from sklearn.model_selection import train_test_split # 选择特征列排除 SaleID 和 price feature_cols [c for c in train.columns if c not in [SaleID, price, regDate, creatDate]] X train[feature_cols] y np.log1p(train[price]) # 对数变换缓解右偏 # 划分验证集 X_train, X_val, y_train, y_val train_test_split(X, y, test_size0.2, random_state42) # 构建 Dataset lgb_train lgb.Dataset(X_train, y_train) lgb_val lgb.Dataset(X_val, y_val, referencelgb_train) # 参数设置 params { objective: regression, metric: mae, boosting_type: gbdt, num_leaves: 31, learning_rate: 0.05, feature_fraction: 0.8, bagging_fraction: 0.8, bagging_freq: 5, verbose: -1, random_state: 42 } # 训练 model lgb.train( params, lgb_train, num_boost_round1000, valid_sets[lgb_val], callbacks[lgb.early_stopping(50), lgb.log_evaluation(100)] ) # 预测并还原 pred_log model.predict(X_val, num_iterationmodel.best_iteration) pred np.expm1(pred_log)逻辑说明np.log1p是log(1x)避免price为 0 时报错。early_stopping(50)表示验证集指标 50 轮不提升就停防止过拟合。num_leaves31是常用起点数据量大可以调到 63 或 127但要注意过拟合。feature_fraction和bagging_fraction是列采样和行采样增加随机性提升泛化。参数怎么改如果验证集 MAE 偏高先降learning_rate到 0.02 并增加num_boost_round如果训练集和验证集差距大降num_leaves或加min_data_in_leaf。这些在 Notebook 里可能没写全但你自己调的时候用得上。3.4 XGBoost 模型训练与对比2--XGBoost.ipynb的逻辑类似但 XGBoost 对缺失值处理和 LightGBM 略有不同。XGBoost 默认把缺失值分到增益最大的方向LightGBM 也支持但参数名不一样。import xgboost as xgb # 构建 DMatrix dtrain xgb.DMatrix(X_train, labely_train) dval xgb.DMatrix(X_val, labely_val) # XGBoost 参数 xgb_params { objective: reg:squarederror, eval_metric: mae, max_depth: 6, eta: 0.05, subsample: 0.8, colsample_bytree: 0.8, seed: 42 } # 训练 xgb_model xgb.train( xgb_params, dtrain, num_boost_round1000, evals[(dval, val)], early_stopping_rounds50, verbose_eval100 ) # 预测 xgb_pred_log xgb_model.predict(xgb.DMatrix(X_val), iteration_range(0, xgb_model.best_iteration)) xgb_pred np.expm1(xgb_pred_log)逻辑说明max_depth6是 XGBoost 常用深度比 LightGBM 的num_leaves更保守。eta相当于 LightGBM 的learning_rate。iteration_range指定用最佳迭代轮数预测避免用全部轮数导致过拟合。两个模型跑完后可以算一下各自的 MAE通常 LightGBM 在这个数据集上会略快略好但差距不会太大。3.5 生成提交文件预测完测试集后按sample_submit.csv的格式写出 CSV。# 用 LightGBM 预测测试集 test_features test[feature_cols] test_pred_log model.predict(test_features, num_iterationmodel.best_iteration) test_pred np.expm1(test_pred_log) # 生成提交文件 submission pd.DataFrame({ SaleID: test[SaleID], price: test_pred }) submission.to_csv(submission/lgb_submission.csv, indexFalse) print(提交文件已生成形状:, submission.shape)逻辑说明SaleID必须和测试集顺序一致price是还原后的真实价格。indexFalse避免多出一列索引。资源包里已经有xgb_submission.csv和submit1.0.csv你可以拿自己的结果和它们对比看是否接近。4. 避坑与排查跑这份源码时最容易翻车的五个地方这一章按「现象 → 原因 → 解决」写都是实际跑这类项目时高频遇到的问题。4.1 现象read_csv报错ParserError或字段错位原因分隔符不对。有些二手车数据集用空格分隔有些用逗号还有的字段里本身含逗号但没加引号。解决先用head -n 3看文件前几行确认分隔符。如果是空格用sep 如果字段错位用sep\s匹配多个空格。还不行就enginepython让 pandas 自己推断。4.2 现象LightGBM 训练时报警告No further splits with positive gain原因min_data_in_leaf或min_child_samples设得太大叶子节点样本不够。解决把min_data_in_leaf从默认 20 降到 10 或 5或者增加num_leaves。如果数据量小这个警告可以忽略不影响最终结果。4.3 现象预测出来的价格全是NaN原因特征列里混入了非数值列比如regDate没拆解就直接扔进去或者notRepairedDamage里的-没处理。解决训练前用X.select_dtypes(include[np.number])筛一遍确保全是数值。另外检查np.expm1的输入是不是NaN如果是说明模型预测阶段就出了问题。4.4 现象提交文件行数和sample_submit.csv对不上原因测试集预测时用了dropna()或过滤了某些行导致SaleID缺失。解决预测阶段不要做任何行过滤缺失值在特征工程阶段就填充好。生成提交文件后用assert len(submission) len(sample_submit)校验一下。4.5 现象两个 Notebook 跑出来的 MAE 差异很大原因特征工程不一致。LightGBM 的 Notebook 可能对某些类别特征做了特殊处理XGBoost 的没有。解决把两个 Notebook 的特征处理逻辑对齐用同一份X_train和y_train。如果还是差异大检查随机种子和验证集划分是否一致。5. 进阶技巧用交叉验证和特征重要性把模型再推一步跑通只是第一步。如果你要拿这份源码做课程设计或毕设光有两个模型的对比还不够加一点进阶操作能让报告厚实不少。5.1 五折交叉验证替代单次划分单次train_test_split的结果波动大换一组随机种子 MAE 可能差几百。用 K 折交叉验证取平均结果更稳。from sklearn.model_selection import KFold kf KFold(n_splits5, shuffleTrue, random_state42) cv_scores [] for fold, (tr_idx, val_idx) in enumerate(kf.split(X)): X_tr, X_val X.iloc[tr_idx], X.iloc[val_idx] y_tr, y_val y.iloc[tr_idx], y.iloc[val_idx] lgb_train lgb.Dataset(X_tr, y_tr) lgb_val lgb.Dataset(X_val, y_val, referencelgb_train) model lgb.train(params, lgb_train, num_boost_round1000, valid_sets[lgb_val], callbacks[lgb.early_stopping(50), lgb.log_evaluation(0)]) pred np.expm1(model.predict(X_val, num_iterationmodel.best_iteration)) mae np.mean(np.abs(pred - np.expm1(y_val))) cv_scores.append(mae) print(fFold {fold1} MAE: {mae:.2f}) print(f平均 MAE: {np.mean(cv_scores):.2f} ± {np.std(cv_scores):.2f})逻辑说明KFold的shuffleTrue保证每折数据分布均匀。early_stopping在每折内部独立触发避免用全局最佳轮数导致信息泄露。最终报告里写「五折交叉验证平均 MAE ± 标准差」比单次划分有说服力得多。5.2 特征重要性分析与特征筛选LightGBM 训练完可以直接输出特征重要性把排名靠后的特征删掉再训练有时能提升泛化。# 获取特征重要性 importance pd.DataFrame({ feature: feature_cols, importance: model.feature_importance(importance_typegain) }).sort_values(importance, ascendingFalse) print(importance.head(15)) # 筛选重要性大于 0 的特征重新训练 selected_features importance[importance[importance] 0][feature].tolist() print(f筛选后特征数: {len(selected_features)})逻辑说明importance_typegain表示用信息增益衡量比split更稳定。通常car_age、kilometer、brand、power会排在前列。如果某些特征重要性为 0说明模型完全没用它可以删掉减少噪声。但注意删特征后要重新跑交叉验证确认 MAE 没变差别盲目删。5.3 模型融合的简单尝试LightGBM 和 XGBoost 的预测结果做加权平均往往比单模型好一点。# 假设 lgb_pred 和 xgb_pred 都是测试集预测结果 final_pred 0.6 * lgb_pred 0.4 * xgb_pred submission pd.DataFrame({SaleID: test[SaleID], price: final_pred}) submission.to_csv(submission/ensemble_submission.csv, indexFalse)权重怎么定看两个模型在验证集上的 MAEMAE 小的给高权重。如果懒得算0.5:0.5 也不会差太多。这一步在课程设计里写「模型融合提升泛化能力」答辩时能多讲两分钟。从那以后我每次拿到这类源码包都先跑一遍原始 Notebook 确认能出结果再动特征工程和参数。先保证基线能跑通再谈优化这个习惯帮我省了无数次「改了半天发现原始代码就有问题」的后悔药。希望这份拆解能帮你顺利跑通自己的二手车价格预测项目少踩几个坑。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

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

尧图内容编辑团队

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

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

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

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

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

网站改版的5个关键决策

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

获取专属建站方案

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

立即免费咨询