阿里云天池:预测二手车交易价格的机器学习项目-高效实现MAE低于500分

最近在学习AI的过程中,老师在针对分析式AI的学习过程中,指导了我们在AI时代,如何使用机器学习 + 大模型完成阿里云天池大赛- 《【AI入门系列】车市先知:二手车价格预测学习赛》。我通过通过使用QWEN3-Coder-plus模型不断对数据的训练,最终达到了490多分,(不是不能完成的更好,而是更希望先完成再完美)。与此同时也自我总结一下在比赛时的学习心得。做一个简单的分享。

1、赛题数据

复制代码
    赛题以预测二手车的交易价格为任务,数据集报名后可见并可下载,该数据来自某交易平台的二手车交易记录,总数据量超过40w,包含31列变量信息,其中15列为匿名变量。为了保证比赛的公平性,将会从中抽取15万条作为训练集,5万条作为测试集A,5万条作为测试集B,同时会对name、model、brand和regionCode等信息进行脱敏。
1.1、常见的字段表
Field Description
SaleID 交易ID,唯一编码
name 汽车交易名称,已脱敏
regDate 汽车注册日期,例如20160101,2016年01月01日
model 车型编码,已脱敏
brand 汽车品牌,已脱敏
bodyType 车身类型:豪华轿车:0,微型车:1,厢型车:2,大巴车:3,敞篷车:4,双门汽车:5,商务车:6,搅拌车:7
fuelType 燃油类型:汽油:0,柴油:1,液化石油气:2,天然气:3,混合动力:4,其他:5,电动:6
gearbox 变速箱:手动:0,自动:1
power 发动机功率:范围 [ 0, 600 ]
kilometer 汽车已行驶公里,单位万km
notRepairedDamage 汽车有尚未修复的损坏:是:0,否:1
regionCode 地区编码,已脱敏
seller 销售方:个体:0,非个体:1
offerType 报价类型:提供:0,请求:1
creatDate 汽车上线时间,即开始售卖时间
price 二手车交易价格(预测目标)
v系列特征 匿名特征,包含v0-14在内15个匿名特征
1.2、评测标准-MAE(Mean Absolute Error)
1.3、结果提交要求

提交前请确保预测结果的格式与sample_submit.csv中的格式一致,以及提交文件后缀名为csv。

以上信息来自于官方赛事要求说明

2、参赛思路

2.1、参赛基础
  • 什么是MAE

    复制代码
    定义:平均绝对误差的数学逻辑-“预测值与真实价的平均差距”来决定误差大小,其对异常值敏感度低于MSE,契合二手车价格分布特点。MAE降低100则意味着:“平均每辆车的预测误差小100元”
  • 分析式AI的基础

    复制代码
    分析式AI,也叫决策式AI,使用特定的数据来训练自己的小模型或工具
            目标:分析和解释数据、提供洞察、预测或决策支持
            用途:用于数据分析、预测建模、风险评估、分类任务等
            技术原理:基于统计分析、机器学习算法等
  • 建模方向的思考

    复制代码
    建模的本质:选择一个合适的模型,并用数据对其进行训练==> 找到数据间的规律
  • 常见的模型

    复制代码
    1)、线性回归
    2)、决策树
    3)、随机森林
    4)、朴素贝叶斯
    5)、SVM
    6)、XGBoost等
    ===========================
    因为我在学习的时候只浅入了解过以上算法,所以知识面也不是很广泛,如果对这方面比较擅长的小伙伴可以在评论区分享关于算法模型的相关内容

    其实在这里我也会有一个疑问:怎样去选择合适的算法?在我对这些算法还一知半解的时候,我的答案只有"尝试",一个一个去尝试去计算其中的MAE预测值,通过不断的尝试去获取更多的可能

  • 特征工程基础

    复制代码
    1、特征处理(Feature Engineering)是指在机器学习模型开发过程中,对原始数据进行预处理,以提取更有价值的特征供模型使用的过程
    2、特征处理过程中通常会涉及到数据清洗、特征编码、特征缩放、特征选择、特征衍生、特征降维等操作。对一些重要代码进行摘录讲解。
    3、特征工程的常见操作步骤:
      3.1、数据预处理
      3.2、特征工程
          A、创建时间特征:将机器不能识别的时间维度转换为能处理的数据(时间多尺度|时间diff算法)
          B、创建品类特征:(如功率、品牌-车型组合、异常值处理、缺失值处理等)
          C、创建统计特征(产品均价、品牌价格对比等)
          D、编码分类特征
      3.3、特征选择和数据准备
          A、删除无用特征
          B、确认所有分类特征被正确标记
          C、转换分类特征为category类型
    =========================================
    常见的特征工程的参数:
      epoch: 训练的轮数,
      batch_size: 每批次处理的样本数量,你设置为 512。
      learning_rate: 学习率,控制模型权重更新的幅度,设置为(即 0.008)。
      device: 计算设备,cuda 表示你将使用 NVIDIA GPU 进行训练。
      num_cols: 数值特征的列名列表,这些列在模型中会被视为连续变量。
      cate_cols: 类别特征的列名列表,这些列会被视为分类变量,可能需要编码或转换处理。
2.2、赛前准备
  • 工具使用

    • TRAE + Qwen3-code-plus + 豆包(特征工程提示词优化)

    • 本地需要支持python3版本以后的环境

  • 数据集准备

只需要从官网上面将这三个数据下载下来后存入你本地的一个目录中就行了

2.3、赛程说明

因为主要是使用AI写代码和梳理逻辑,所以我们只需要做到和AI对话,确保其能够听明白我们的指令就可以了。在初次操作时,我一共提交了如下指令给Qwen。

复制代码
指令1: 
        编写Python代码,读取 used_car_train_20200313.csv 和used_car_testB_20200313.csv 的前5行数据,显示全部列 ================================================== 
指令说明:读取前面的数据是想要AI快速了解文档内容及结构,快速学习的过程
复制代码
指令2: 
        运行python 将这些数据表的字段含义,写入到 .md ================================================= 
以下就是整个md文档会生成的内容: ​
 ## 训练数据集 (used_car_train_20200313.csv) | 
字段名 | 数据类型 | 描述 | |--------|----------|------| 
| SaleID | int | 销售ID,唯一标识每辆车的销售记录 |
| name | int | 车辆名称(可能是经过编码的车辆型号) |
| regDate | int | 上牌日期,格式为 YYYYMMDD | 
| model | float | 车型,具体的车型编号 | 
| brand | float | 品牌,品牌编号 | 
| bodyType | float | 车身类型,如轿车、SUV等 | 
| fuelType | float | 燃料类型,如汽油、柴油、电动等 |
| gearbox | float | 变速箱类型,手动挡或自动挡 |
| power | int | 发动机功率(马力或其他单位) |
| kilometer | float | 行驶里程(万公里) |
| notRepairedDamage | float | 是否有未修复的损伤(0表示无,1表示有) |
| regionCode | int | 地区编码,表示车辆所在地区 |
| seller | int | 卖家类型(0或1,可能是个体或经销商) |
| offerType | str | 报价类型(通常是"offer") |
| creatDate | int | 创建日期,格式为 YYYYMMDD |
| price | int | 价格(万元),这是预测的目标变量 |
| v_0 ~ v_14 | float/int | 15个匿名化特征,具体的业务含义未知 |
​
## 测试数据集 (used_car_testB_20200421.csv)
| 字段名 | 数据类型 | 描述 |
|--------|----------|------|
| SaleID | int | 销售ID,唯一标识每辆车的销售记录 |
| name | int | 车辆名称(可能是经过编码的车辆型号) |
| regDate | int | 上牌日期,格式为 YYYYMMDD |
| model | float | 车型,具体的车型编号 |
| brand | float | 品牌,品牌编号 |
| bodyType | float | 车身类型,如轿车、SUV等 |
| fuelType | float | 燃料类型,如汽油、柴油、电动等 |
| gearbox | float | 变速箱类型,手动挡或自动挡 |
| power | int | 发动机功率(马力或其他单位) |
| kilometer | float | 行驶里程(万公里) |
| notRepairedDamage | float | 是否有未修复的损伤(0表示无,1表示有) |
| regionCode | int | 地区编码,表示车辆所在地区 |
| seller | int | 卖家类型(0或1,可能是个体或经销商) |
| offerType | str | 报价类型(通常是"offer") |
| creatDate | int | 创建日期,格式为 YYYYMMDD |
| v_0 ~ v_14 | float/int | 15个匿名化特征,具体的业务含义未知 |
​
> 注意:测试数据集中不包含"price"字段,因为这就是我们要预测的目标变量。
​
## 特征说明
- **regDate & creatDate**: 日期型变量,需要可能需要转化为相对时间或提取年/月特征
- **bodyType, fuelType, gearbox**: 分类型变量,数值表示不同类别
- **power, kilometer, price**: 数值型变量
- **notRepairedDamage**: 缺失值用"-"表示,实际为0或1的二分类变量
- **v_0-v_14**: 匿名化的特征,具体含义未知,可能包含了车辆的其他属性或派生特征
复制代码
指令3:
    帮我进行EDA (explore data analysis)
==============================================
此步骤就会生成各个类型的数据图表展示于你本地
​
## 1. 数据概览
- **训练集**: 150,000 行 × 31 列
- **测试集**: 50,000 行 × 30 列
- **主要区别**: 测试集不包含目标变量 'price',这是我们要预测的列
​
## 2. 缺失值分析
### 训练集缺失值
| 字段 | 缺失数量 | 缺失比例 |
|------|---------|---------|
| model | 1 | 0.000667% |
| bodyType | 4,506 | 3.004% |
| fuelType | 8,680 | 5.787% |
| gearbox | 5,981 | 3.987% |
### 测试集缺失值
| 字段 | 缺失数量 | 缺失比例 |
|------|---------|---------|
| bodyType | 1,504 | 3.008% |
| fuelType | 2,924 | 5.848% |
| gearbox | 1,968 | 3.936% |
### 特殊缺失值
- 'notRepairedDamage' 列使用 '-' 表示缺失值
  - 训练集: 24,324 个 '-' 值
  - 测试集: 8,069 个 '-' 值
  
## 3. 数据类型分析
### 数值型字段
- SaleID, name, regDate, model, brand, bodyType, fuelType, gearbox, power, kilometer, regionCode, seller, offerType, creatDate, price (仅训练集), v_0-v_14
### 非数值型字段
- notRepairedDamage: object 类型,包含 '0.0', '1.0' 和 '-' 值
​
## 4. 价格分布分析 (仅训练集)
- **价格范围**: 11 - 99,999 元
- **平均价格**: 5,923.33 元
- **中位数价格**: 3,250 元
- **价格标准差**: 7,502.00 元
- **异常值**: 10,353 个 (占 6.90%)
价格分布呈现明显的右偏态,说明存在较多高价异常值。
​
## 5. 关键发现
1. **缺失值处理**:
   - 三个关键特征(bodyType, fuelType, gearbox)存在约3-6%的缺失
   - notRepairedDamage 列使用特殊符号 '-' 表示缺失,需进行数据清洗
2. **数据不均衡**:
   - 价格分布极不均匀,存在极端高价车影响模型训练
3. **数据特征**:
   - 时间字段(regDate, creatDate)编码为 YYYYMMDD 格式
   - 匿名特征 v_0-v_14 涵盖了较广的数值范围
​
## 6. 建议的数据预处理步骤
1. 处理缺失值:
   - 对 bodyType, fuelType, gearbox 使用中位数或众数填充,或使用模型预测
   - 将 '-' 转换为 NaN,然后对 notRepairedDamage 进行适当填充
2. 异常值处理:
   - 对价格进行对数变换或使用 IQR 方法处理异常值
3. 特征工程:
   - 从时间字段中提取年份、月份信息
   - 对分类变量进行独热编码或标签编码
4. 数据标准化:
   - 对数值型特征进行标准化或归一化
复制代码
指令4:
    帮我查看是否有字段值缺失
===============================================
工具会自动为你生成缺失字段并提交补齐建议
复制代码
指令5:
    去掉 SaleID,使用随机森林构建price预测模型,使用训练集进行学习,使用测试集进行预测得到price,写入到 .csv,表头是 SaleID, price
================================================
指令说明:生成.csv的文件,此时你可以去提交你的测算结果,看一下结果是否符合提交预期并判定一下你的分数值。大约在800-900之间 甚至更高
复制代码
指令6:
    使用XGBoost进行预测,同时使用验证集,在训练的时候可以看到验证集的MAE
===============================================================
此时使用XGBoost进行预测,可以生成一个新的.csv的文件,可以提交分数查看分数值
(博主在这个位置踩了很多坑,这里会涉及到一个XGBoost的缺陷即“过拟合”,导致本地验证集的MAE很低,但是线上的MAE直接反向提高至1000多==》因此直接建议使用catBoost)
复制代码
指令7(可选):
    使用更多的训练轮数,更小的学习率,加入早停法,此外你看下特征工程还有哪些需要优化的
=================================================================
这里是通过对XGBoos或者catBoost的各项参数进行调整,来达到更低的MAE结果。但会发现整体的影响度其实不大。但也能够降低到700左右
复制代码
指令8(加入特征工程==》超多):
   1、针对数据预处理:
  a、缺失值处理:
  高价值特征(如保养记录、过户次数):构造「是否缺失」标记(has_maintain_null=1/0)+ 分组填充(按「品牌 + 车型」的均值 / 中位数填充)
  低价值特征:若缺失率 > 50%,直接删除;否则用众数填充(适合类别特征)或中位数填充(适合数值特征):
  b、异常值修正:
  数值特征(里程、价格):用「3σ 法则」或「分位数法(1%/99%)」识别异常,然后用「品牌 + 车龄 + 车型」的分组中位数替换(保留合理波动,如跑车里程低但价格高)
  构造异常标记:对修正后的异常样本,添加「is_abnormal_mileage=1」特征
  c、数据类型与冗余清理:
  时间特征:将「上牌日期」转换为「车龄 = 当前年份 - 上牌年份」(连续特征)+「上牌季节」(离散特征:Q1/Q2/Q3/Q4,不同季节上牌的车型保值率有差异),删除原始上牌日期(与车龄完全共线性)
  冗余特征:删除方差 <0.01 的特征(如所有样本均为「非事故车」)、删除 Pearson 相关系数> 0.8 的高相关特征(如「排量」与「马力」高度相关,保留排量)
2、基础特征构造
  a、时间维度:车龄平方/立方、上牌月份(如 12 月上牌的车可能比 1 月保值,因按年份算车龄更短)
  b、数值维度:年均里程=里程/车龄(判断车辆使用强度,年均里程 > 3 万公里可能是运营车,保值率低)、排量等级、配置丰富度(若有多个配置特征,如倒车影像、全景天窗,构造计数特征:config_count=配置1+配置2+...,配置越多保值率越高)
  c、类别维度:品牌档次(按业务聚类:豪华品牌 / BBA / 合资品牌 / 自主品牌,如 BBA 品牌单独标记,保值率显著高于其他)、车型类型(按用途聚类:轿车 / SUV/MPV/ 跑车
3、交叉特征构造:
  a、品牌 + 车型:brand_model=品牌_车型
  b、品牌 + 车龄:brand_age=品牌_车龄区间
  c、地区 + 车型:region_car_type=地区_车型
  d、变速箱 + 品牌档次:gearbox_brand=变速箱_品牌档次(豪华品牌自动挡更保值,自主品牌手动挡性价比更高,价格波动小)。
  e、车况相关交叉:maintain_times_age=保养次数/车龄
4. 业务逻辑特征
* 热门度特征:
    * model_popularity=车型出现频次/总样本数(出现频次高的是热门车型,保值率高)。
    * brand_popularity=品牌销量占比(按品牌样本数占比计算,热门品牌议价能力强)。
* 车况信号特征:
    * is_first_car=1 if 过户次数=0 else 0(一手车保值率显著高于多手车)。
    * is_accident_free=1 if 事故记录=无 else 0(无事故车是核心溢价点)。
    * maintain_regular=1 if 保养记录≥车龄×1.5 else 0(定期保养标记,1.5 是经验阈值,可通过 EDA 调整)。
* 市场供需特征:
    * region_price_level=地区均价/全国均价(判断地区价格水平,如一线城市价格更高)。
    * season_demand=1 if 上牌季节=Q4 else 0(Q4 是购车旺季,价格略高)。
​
5. 特征筛选与编码
* 特征筛选:
    * 方差筛选:删除方差 < 0.01 的特征(无区分度)。
    * 重要性筛选:用 CatBoost 的 feature_importances_ 排序,保留前 80% 的特征(或删除重要性 < 0.001 的特征)。
    * 递归特征消除(RFE):结合 CatBoost 作为基模型,逐步删除不重要特征,保留最优子集。
* 特征编码:
    * 低基数类别(如变速箱:自动 / 手动、燃油类型:汽油 / 柴油):用 One-Hot 编码(CatBoost 自动支持,无需手动处理)。
    * 高基数类别(如品牌、车型, cardinality>30):用「交叉验证目标编码」(避免过拟合,如按 5 折划分,用训练集的价格均值编码验证集,防止数据泄露)。
    * 有序类别(如车龄区间:1-3 年 / 3-5 年 / 5-10 年):用标签编码(保持有序性)。
=========================================================================
我大概设置了如上的特征工程进行优化,至此分数下降到500多。可以再针对一次使用更多的训练轮数,更小的学习率,加入早停法结合大模型推荐的方法进行优化,很快就可以下到400多了

当然以上只是我的一个实现思路,具体情况大家可以再结合自己的AI生成的逻辑进行调优

2.4、赛程结果及优化思路

最终我获取的成绩是490分,每一步的分数提升都是我对决策和优化+工具的高效实现,其中我觉得有如下可以侧重考虑的点:

  1. 特征工程的重要性远大于参数调优:我个人认为在这个过程中10%参数调优 + 90%特征工程。特征工程能够决定模型上线,参数调整只是尽可能能够跑出上限的可能性。

  2. 如果你的验证集的MAE 与训练集的MAE 相差过大 => 可能是因为过拟合,模型的复杂程度太高、训练数据量不足、训练时间过长、缺乏正则化的措施等都会模型记住训练数据的异常值、先训练集上表现出"完美记忆"。数据拟合会很容易出现幻觉且对新数据的泛化能力很差。

  3. 数据探索非常重要==》EDA,必做的分析有缺失值 / 异常值分布、特征与目标相关性、目标变量分布,整理出影响二手车价格的核心特征,明确处理方案后,大模型的使用会事半功倍

  4. 可以分段进行特征优化:按「预处理→基础特征→交叉特征→业务特征」逐步添加,每一步训练后观察 MAE 变化,更能够直观的感受到MAE变化的趋势,你也能够更快的了解特征工程差异化给最终结果带来的优化

  5. 模型调参的过程中很容易出现泛化情况,针对其优化你可以加入交叉验证、早停策略、还有训练 出多个不同参数的 CatBoost 模型,取预测结果的均值(进一步降低方差)

  6. 多尝试,别怕出错:先完成再完美。即使可能分数差别存在,但每一次越低分就会说明你的思考方式是没有问题

3、个人学习心得

3.1、工具使用的心得

在我们的提示词工程时,精准提需求是关键:把"模糊需求"拆成"具体操作步骤",工具才能输出有用代码,可以借助三方工具如Trae的提示词优化器来完善你的提示词,AI更懂AI,如果你想手写提示词,可以参考我的上一篇文章《deepseek和提示词工程》,希望能够帮助你写出更准确的提示词

核心决策在自己:工具是"执行者",模型选什么、特征留哪些、参数范围定多少,需要自己基于业务和数据判断,取用核心特征工程,在核心特征工程上进行加权。会更加容易跑出你想要的结果。

AI建模的本质是"数据处理+特征工程+模型优化",代码只是实现手段。我有看到很多通过手写代码完成比赛的,诚然他们超厉害,但AI的使用会让我们更加高效的去解决思路。以后代码也只会是我们提出问题的实现手段。

3.2、给代码薄弱的你我的一些小建议

别怕"不会写代码":qwen3-code-plus等工具能帮你落地,AI时代重点先学"做决策"

学会"拆解需求":把大任务拆成"数据读取→处理→特征→建模→提交"小步骤,逐个让工具实现

多做"结果校验":用业务常识(如车龄越大价格越低)判断工具输出是否合理

长期规划:工具是过渡,我开始基于工具生成的代码学习Python,逐步建立自己的代码能力

核心信念:AI入门的关键是"解决问题的能力",代码和工具都是为这个目标服务的

相关推荐
NAGNIP4 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab5 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab5 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
哥不是小萝莉6 小时前
OpenClaw 架构设计全解析
ai
AngelPP9 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年9 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼9 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS9 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
warm3snow10 小时前
Claude Code 黑客马拉松:5 个获奖项目,没有一个是"纯码农"做的
ai·大模型·llm·agent·skill·mcp
天翼云开发者社区10 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤