ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

二手车价格预测机器学习作业:线性回归、SVR、LightGBM与CNN全流程实战

二手车价格预测机器学习作业:线性回归、SVR、LightGBM与CNN全流程实战 简介这份资源面向人工智能、机器学习方向的课程期末作业与毕业设计需求提供一套完整的二手车交易价格预测评估系统实现方案适合具备Python基础、希望理解回归与深度学习建模全流程的初学者和进阶学习者。压缩包共19个文件约55.92MB以csv数据与预测结果、py源码、ipynb笔记为主另含h5模型权重、npy参数文件、md说明与txt特征清单覆盖数据、代码、模型与结果各环节。项目围绕used_car_train_20200313.csv数据集展开分别实现支持向量机回归、多元线性回归、LightGBM与CNN四类模型并给出测试集价格预测结果、标准化数据、模型参数及特征交叉后经Spearman筛选的冗余特征代码注释详尽新手也能读懂。已有4123人学习下载读者可据此掌握特征工程、模型训练与评估对比的完整思路并直接复用为课程作业或毕设基础。1. 从一份二手车数据集说起这套机器学习作业到底能跑出什么二手车价格预测是个特别适合练手的机器学习场景特征维度够杂、缺失值够多、异常值够脏而且业务含义直观——车龄、公里数、品牌、变速箱类型这些字段看一眼就知道大概该卖多少钱。但真拿到一份used_car_train_20200313.csv这样的原始数据很多人第一反应是懵的15 万条训练样本、30 来个字段价格那一列还带着长尾分布直接丢进模型大概率翻车。这套资源把整个流程拆成了四个独立模型支持向量机回归、多元线性回归、LightGBM、CNN。每个模型都有对应的训练代码、预测结果 CSV 和中间产物标准化数据、模型参数.npy、Keras 权重.h5。它不是那种只给一个train.py就完事的作业包而是把数据清洗、特征工程、模型对比、结果输出全链路都留了痕迹。适合正在做机器学习期末大作业、毕业设计或者想拿一个完整项目练手的人——尤其是那种“知道理论但没从头跑通过一个完整 pipeline”的阶段。2. 四个模型的代码结构与数据流先搞清楚谁依赖谁2.1 目录拆解与文件依赖关系拿到压缩包解压后根目录下是machine_learning_homework-master里面按模型分了四个文件夹。别急着挨个打开.py文件先理清数据流向否则很容易在某个脚本里找不到它要读的 CSV。核心数据文件只有一个used_car_train_20200313.csv。这是原始训练集所有模型都从它出发。但四个模型对数据的处理方式不同多元线性回归先把原始数据标准化产出linear_regression_standardize_data.csv训练后得到模型参数w_data.npy最后输出测试集预测linear_regression_test_final.csv。SVR直接读原始数据内部做编码和缩放输出svr_final(1).csv。LightGBM分两个版本——优化前模型和特征交叉十折交叉验证模型。特征交叉后用 Spearman 筛出冗余特征存到相似度较高的特征.txt训练集和测试集预测分别是lgb_train_final.csv和lgb_test_final.csv。CNN把特征整理成X_data.csv和Y_data.csv训练后保存模型权重20.h5测试集预测在CNN_test_final.csv。这里有个容易忽略的点X_data.csv和Y_data.csv不是原始数据而是 CNN 专用的特征矩阵和标签。如果你直接拿它们去喂 LightGBM维度对不上。2.2 环境准备与依赖安装代码是 Python 写的没有requirements.txt但根据 import 语句可以反推依赖。我一般会先建一个干净虚拟环境避免和系统里的包版本打架python -m venv venv_car source venv_car/bin/activate # Windows 用 venv_car\Scripts\activate pip install numpy pandas scikit-learn lightgbm tensorflow keras matplotlib seaborn注意 TensorFlow 和 Keras 的版本兼容性。.h5文件是老版 Keras 保存格式TensorFlow 2.x 自带的tf.keras能读但如果代码里写的是from keras.models import load_model可能需要单独装keras包并锁定版本。我试过 TensorFlow 2.10 Keras 2.10 能正常加载再新的版本可能会报Unknown layer之类的错。2.3 数据字段速查与预处理要点used_car_train_20200313.csv的字段没有官方说明文档但根据常见二手车数据集和代码里的引用核心列包括price目标列、brand、bodyType、fuelType、gearbox、power、kilometer、notRepairedDamage、regDate、creatDate等。其中price分布右偏严重直接做回归会让模型偏向高价样本。预处理阶段有几个固定动作import pandas as pd import numpy as np df pd.read_csv(used_car_train_20200313.csv, sep ) # 缺失值处理类别型填 -1数值型填中位数 cat_cols [bodyType, fuelType, gearbox] for col in cat_cols: df[col] df[col].fillna(-1) num_cols [power, kilometer] for col in num_cols: df[col] df[col].fillna(df[col].median()) # 日期转数值regDate 和 creatDate 转成天数差 df[regDate] pd.to_datetime(df[regDate], format%Y%m%d, errorscoerce) df[creatDate] pd.to_datetime(df[creatDate], format%Y%m%d, errorscoerce) df[used_days] (df[creatDate] - df[regDate]).dt.days df df.drop([regDate, creatDate], axis1) # 目标列对数变换缓解长尾 df[price_log] np.log1p(df[price])这段代码的逻辑是先把类别缺失当成一个独立类别-1数值缺失用中位数兜底然后把日期转成“使用了多少天”这个连续特征最后对价格做log1p变换。参数上sep 是因为这个数据集用空格分隔不是逗号。如果你用默认的read_csv会读成一整列。3. 逐个模型跑通从线性回归到 LightGBM 再到 CNN3.1 多元线性回归最简 baseline 与标准化陷阱线性回归代码在多元线性回归代码.py里。它的价值不是预测多准而是给你一个性能下限——如果 LightGBM 跑出来还不如线性回归那肯定是特征工程或数据泄漏出了问题。关键步骤是标准化。代码里用StandardScaler对特征做 Z-score 变换然后保存成linear_regression_standardize_data.csv。这里有个坑标准化必须只在训练集上 fit然后 transform 测试集。如果先把全量数据标准化再切分测试集的均值和方差就泄漏到了训练过程。from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LinearRegression from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error, r2_score # 假设 df 已经过预处理feature_cols 是特征列 X df[feature_cols].values y df[price_log].values 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) lr LinearRegression() lr.fit(X_train_scaled, y_train) # 保存模型参数 np.save(w_data.npy, lr.coef_) y_pred lr.predict(X_test_scaled) print(RMSE:, np.sqrt(mean_squared_error(y_test, y_pred))) print(R2:, r2_score(y_test, y_pred))w_data.npy存的是回归系数加载时用np.load(w_data.npy)。注意这个系数是对应标准化后的特征不是原始尺度。如果你想解释“公里数每增加 1 万价格降多少”得把系数除以对应特征的标准差。线性回归在这个数据集上 R² 通常只有 0.3~0.5因为价格和特征之间不是纯线性关系。但它跑得快适合验证数据管道是否通畅。3.2 SVR 支持向量机回归核函数选择与调参边界SVR 代码在张立静-SVR作业代码.ipynb和张立静作业代码.py里。SVR 对特征尺度极度敏感所以代码里必然有标准化步骤。它的优势是能拟合非线性关系但缺点是样本量一大就慢得离谱——15 万条数据用 RBF 核训练时间可能按小时算。我一般会先抽样跑一遍确认参数范围再上全量from sklearn.svm import SVR from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error import numpy as np # 抽样 2 万条加速调试 df_sample df.sample(n20000, random_state42) X df_sample[feature_cols].values y df_sample[price_log].values X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) scaler StandardScaler() X_train scaler.fit_transform(X_train) X_test scaler.transform(X_test) svr SVR(kernelrbf, C1.0, epsilon0.1, gammascale) svr.fit(X_train, y_train) y_pred svr.predict(X_test) rmse np.sqrt(mean_squared_error(y_test, y_pred)) print(SVR RMSE:, rmse)参数说明C控制惩罚力度越大越容易过拟合epsilon是不敏感损失带宽越大支持向量越少、模型越简单gammascale是自动按特征方差设核系数。如果 RMSE 比线性回归还差先把C调到 10 或 100 试试再检查特征里有没有没处理的类别变量。svr_final(1).csv是测试集预测结果里面应该是两列样本 ID 和预测价格。注意这个文件是原始尺度还是对数尺度——如果代码里对 y 做了 log 变换输出前要np.expm1还原。3.3 LightGBM特征交叉与十折交叉验证的工程细节LightGBM 是这套资源里最接近“能打”的模型。代码分两个文件lightGBM模型优化前模型代码.py和lightGBM特征交叉后及十折交叉验证模型代码.py。后者是重点。特征交叉的思路是把两个类别特征组合成一个新特征比如brand_gearbox brand * 100 gearbox。这样能捕捉“某品牌某变速箱”的联合效应。但交叉后特征维度会膨胀所以代码里用 Spearman 相关系数筛掉相似度高的冗余特征结果存在相似度较高的特征.txt。import lightgbm as lgb from sklearn.model_selection import KFold from sklearn.metrics import mean_squared_error import numpy as np # 假设 X_train, y_train 已经准备好 kf KFold(n_splits10, shuffleTrue, random_state42) oof_preds np.zeros(len(X_train)) test_preds np.zeros(len(X_test)) params { objective: regression, metric: rmse, learning_rate: 0.05, num_leaves: 31, max_depth: -1, feature_fraction: 0.8, bagging_fraction: 0.8, bagging_freq: 5, verbose: -1, random_state: 42 } for fold, (trn_idx, val_idx) in enumerate(kf.split(X_train)): X_trn, X_val X_train[trn_idx], X_train[val_idx] y_trn, y_val y_train[trn_idx], y_train[val_idx] dtrain lgb.Dataset(X_trn, labely_trn) dval lgb.Dataset(X_val, labely_val, referencedtrain) model lgb.train( params, dtrain, num_boost_round2000, valid_sets[dval], callbacks[lgb.early_stopping(100), lgb.log_evaluation(200)] ) oof_preds[val_idx] model.predict(X_val, num_iterationmodel.best_iteration) test_preds model.predict(X_test, num_iterationmodel.best_iteration) / kf.n_splits print(OOF RMSE:, np.sqrt(mean_squared_error(y_train, oof_preds)))参数上learning_rate0.05配合num_boost_round2000和早停是常见组合。num_leaves31是默认值如果过拟合就降到 15 或 7。feature_fraction和bagging_fraction用来增加随机性、防止过拟合。十折交叉验证的目的是让每条训练样本都当过一次验证集这样 OOF 预测更稳定也方便后续做模型融合。lgb_train_final.csv和lgb_test_final.csv分别是训练集和测试集的预测结果。注意训练集预测用的是 OOF 方式不是直接model.predict(X_train)——后者会过拟合评估指标虚高。3.4 CNN 模型把表格数据当图像处理的取巧与代价CNN 部分在cnn文件夹里核心文件是cnn代码.py、X_data.csv、Y_data.csv和20.h5。把表格数据喂给 CNN 是个有点“取巧”的做法把每个样本的特征向量 reshape 成二维矩阵然后用卷积核去提取局部模式。import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout from tensorflow.keras.optimizers import Adam # 假设 X_data.csv 和 Y_data.csv 已经准备好 X np.loadtxt(X_data.csv, delimiter,) Y np.loadtxt(Y_data.csv, delimiter,) # reshape 成 CNN 需要的 4D 张量(样本数, 高, 宽, 通道) X X.reshape(X.shape[0], 8, 8, 1) # 假设特征数 64排成 8x8 model Sequential([ Conv2D(32, (3, 3), activationrelu, input_shape(8, 8, 1)), MaxPooling2D((2, 2)), Conv2D(64, (3, 3), activationrelu), MaxPooling2D((2, 2)), Flatten(), Dense(128, activationrelu), Dropout(0.3), Dense(1) ]) model.compile(optimizerAdam(learning_rate0.001), lossmse, metrics[mae]) model.fit(X, Y, epochs50, batch_size64, validation_split0.2) model.save(20.h5)20.h5是 Keras 保存的完整模型结构权重加载用from tensorflow.keras.models import load_model; model load_model(20.h5)。CNN_test_final.csv是测试集预测结果。这里最大的坑是 reshape 的维度。如果X_data.csv的特征数不是完全平方数就得补零或者截断。而且 CNN 对表格数据的归纳偏置局部平移不变性并不天然成立所以效果不一定比 LightGBM 好。它的价值更多在于“作业要求覆盖多种模型类型”。4. 避坑与排查跑这套代码时最容易翻车的五个地方4.1 文件路径与分隔符不匹配现象pd.read_csv(used_car_train_20200313.csv)读出来只有一列列名是整行字符串。原因这个数据集用空格分隔不是逗号。默认sep,会把整行当成一个字段。解决显式指定sep 如果空格数不固定就用sep\s配合enginepython。4.2 标准化顺序导致数据泄漏现象线性回归和 SVR 的测试集 R² 高得离谱0.9但换一批数据就崩。原因先对全量数据做fit_transform再切分训练测试集。测试集的统计量泄漏到了训练过程。解决严格按train_test_split→fit训练集 →transform测试集的顺序。linear_regression_standardize_data.csv如果是在切分前生成的建议重新跑一遍。4.3 LightGBM 训练集预测指标虚高现象lgb_train_final.csv对应的 RMSE 远低于测试集以为模型过拟合。原因训练集预测用的是model.predict(X_train)模型见过这些样本指标自然好。解决用十折交叉验证的 OOF 预测来评估训练集性能。代码里oof_preds就是干这个的别直接用model.predict。4.4 CNN 输入维度对不上现象X_data.csv加载后 reshape 报错cannot reshape array of size N into shape (M,8,8,1)。原因特征数不是 64或者 CSV 里有多余的索引列。解决先print(X.shape)确认列数去掉索引列pd.read_csv(..., index_col0)然后按实际特征数调整 reshape 参数。如果特征数不是平方数用np.pad补零到最近的平方数。4.5 Keras 模型加载报 Unknown layer现象load_model(20.h5)抛出ValueError: Unknown layer: ...。原因保存模型时的 Keras 版本和加载时的版本不一致或者模型里用了自定义层。解决统一 TensorFlow/Keras 版本建议用tensorflow.keras而不是独立keras包。如果必须跨版本加载时加compileFalse然后手动重新编译。5. 从跑通到跑好特征筛选与模型融合的实操技巧把四个模型都跑通之后下一步自然是让结果好看一点。这套资源里已经埋了一个线索相似度较高的特征.txt。这个文件是 LightGBM 特征交叉后用 Spearman 相关系数筛出来的冗余特征列表。Spearman 衡量的是单调相关性比 Pearson 更适合类别编码后的特征。我一般会这样做特征筛选先算所有特征两两之间的 Spearman 系数把绝对值大于 0.9 的成对特征标记出来然后从每对里删掉一个——删哪个看 LightGBM 的特征重要性保留重要性高的那个。import pandas as pd import numpy as np from scipy.stats import spearmanr import lightgbm as lgb # 假设 df 是预处理后的数据feature_cols 是特征列 corr_matrix df[feature_cols].corr(methodspearman).abs() upper corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k1).astype(bool)) to_drop [column for column in upper.columns if any(upper[column] 0.9)] # 用 LightGBM 重要性决定保留哪个 dtrain lgb.Dataset(df[feature_cols], labeldf[price_log]) model lgb.train({objective: regression, verbose: -1}, dtrain, num_boost_round100) importance pd.Series(model.feature_importance(), indexfeature_cols) # 对每对高相关特征删掉重要性低的 for col in to_drop: correlated upper.index[upper[col] 0.9].tolist() for c in correlated: if importance[col] importance[c]: to_drop.append(c) if c not in to_drop else None final_features [f for f in feature_cols if f not in set(to_drop)] print(保留特征数:, len(final_features))这段代码的逻辑是先找高相关特征对再用 LightGBM 的重要性打分决定去留。参数上0.9 是经验阈值调到 0.95 会更保守调到 0.85 会更激进。feature_importance()默认返回 split 次数也可以设importance_typegain用信息增益。模型融合是另一个提分点。四个模型的预测结果 CSV 都在可以直接读进来做加权平均import pandas as pd import numpy as np from sklearn.metrics import mean_squared_error # 读取各模型测试集预测 lr_pred pd.read_csv(linear_regression_test_final.csv)[price].values svr_pred pd.read_csv(svr_final(1).csv)[price].values lgb_pred pd.read_csv(lgb_test_final.csv)[price].values cnn_pred pd.read_csv(CNN_test_final.csv)[price].values # 简单加权平均权重按验证集 RMSE 反比分配 weights np.array([0.1, 0.15, 0.6, 0.15]) # LightGBM 权重最高 ensemble (lr_pred * weights[0] svr_pred * weights[1] lgb_pred * weights[2] cnn_pred * weights[3]) # 如果各模型输出的是对数价格记得还原 ensemble_price np.expm1(ensemble)权重不是拍脑袋定的。我一般会先在验证集上算每个模型的 RMSE然后取 RMSE 倒数归一化作为权重。LightGBM 通常权重最高线性回归和 SVR 权重低一些CNN 看情况——如果它的 RMSE 比线性回归还差权重直接给 0 也不可惜。还有一个容易忽略的点lgb_train_final.csv是 OOF 预测可以用来做 stacking。把四个模型的 OOF 预测作为新特征再训一个线性回归或小 LightGBM 做元学习器往往比简单加权再涨一点。但要注意stacking 的元学习器必须用交叉验证训练否则同样会过拟合。从那以后我每次拿到新的表格数据集都强制先跑一遍线性回归当 baseline再上 LightGBM最后看情况补 SVR 或神经网络。这套二手车作业包的好处是四个模型的结果文件都留着你可以直接对比 RMSE不用从零搭管道。希望帮到你。本文还有配套的精品资源点击获取
返回列表