当前位置: 首页 > news >正文

基于决策树模型的汽车价格预测分析

一、整体流程概览

这份代码实现了一个完整的机器学习预测流程,核心目标是通过汽车的各项特征预测其价格。整体流程分为 6 个主要步骤:

  1. 模拟生成汽车数据集(含价格标签)
  2. 数据预处理(清洗、编码、特征选择)
  3. 探索性数据分析(可视化数据分布和关系)
  4. 基础模型训练与评估
  5. 网格搜索优化模型参数
  6. 特征重要性分析

使用的核心算法是决策树回归器DecisionTreeRegressor),因为它能很好地捕捉特征与价格之间的非线性关系,且结果易于解释。

二、详细代码讲解

1. 模拟生成汽车数据库(generate_car_data函数)

这一步的目标是创建一个贴近真实的汽车数据集,包含影响价格的关键特征和目标变量(价格)。

def generate_car_data(n_samples=1000):np.random.seed(42)  # 固定随机种子,确保结果可复现
  • np.random.seed(42):设置随机种子,保证每次运行生成相同的数据,便于调试和结果复现。
    brands = {'luxury': ['Mercedes', 'BMW', 'Audi', 'Lexus'],'mid_range': ['Toyota', 'Honda', 'Ford', 'Volkswagen'],'economy': ['Hyundai', 'Kia', 'Chevrolet', 'Fiat']
    }# 品牌概率计算(总和为1)
    luxury_prob = 0.2  # 豪华品牌整体占比20%
    mid_range_prob = 0.5  # 中端品牌50%
    economy_prob = 0.3  # 经济品牌30%# 每个品牌的概率 = 类别总概率 / 类别内品牌数量
    luxury_p = [luxury_prob / 4] * 4  # 4个豪华品牌,每个占5%
    mid_range_p = [mid_range_prob / 4] * 4  # 4个中端品牌,每个占12.5%
    economy_p = [economy_prob / 4] * 4  # 4个经济品牌,每个占7.5%
    p = luxury_p + mid_range_p + economy_p  # 合并概率列表(总和=1)

  • 解决了之前的ValueError:通过按类别分配总概率,再平均到每个品牌,确保概率总和为 1。
  • 1.2 特征生成
    data = {'brand': np.random.choice(brands['luxury'] + brands['mid_range'] + brands['economy'],size=n_samples, p=p),'age': np.random.randint(0, 15, size=n_samples),  # 车龄0-14年'mileage': np.random.lognormal(4.5, 0.8, size=n_samples) + np.random.randint(0, 50, size=n_samples),  # 里程数(对数正态分布,模拟真实车辆里程)'engine_size': np.round(np.random.uniform(1.0, 4.5, size=n_samples), 1),  # 发动机排量1.0-4.5L'horsepower': np.random.randint(80, 350, size=n_samples),  # 马力80-349匹'fuel_type': np.random.choice(['gasoline', 'diesel', 'hybrid', 'electric'], p=[0.6, 0.2, 0.15, 0.05]),  # 燃油类型(汽油车占比最高)'transmission': np.random.choice(['manual', 'automatic'], p=[0.3, 0.7]),  # 变速箱(自动挡占比70%)'maintenance_rating': np.round(np.random.normal(7, 1.5, size=n_samples)).clip(1, 10),  # 保养评分(1-10分,均值7分)'accident_count': np.random.choice([0, 1, 2, 3], p=[0.7, 0.2, 0.08, 0.02]),  # 事故次数(多数车辆无事故)'seats': np.random.choice([2, 4, 5, 7, 8], p=[0.1, 0.2, 0.5, 0.15, 0.05])  # 座位数(5座车最常见)
    }

  • 特征选择贴合真实场景:车龄、里程数、发动机大小等均为影响汽车价格的关键因素。
  • 分布设计合理:例如多数车辆无事故(accident_count=0占 70%)、5 座车最常见(占 50%)。
  • 价格由 “基础价格 + 调整因素” 构成,模拟真实定价逻辑:

    # 基础价格(按品牌档次)
    brand_base_price = {brand: 50000 for brand in brands['luxury']}  # 豪华品牌基础价5万
    brand_base_price.update({brand: 30000 for brand in brands['mid_range']})  # 中端3万
    brand_base_price.update({brand: 15000 for brand in brands['economy']})  # 经济1.5万
    df['base_price'] = df['brand'].map(brand_base_price)# 价格调整因素(核心逻辑)
    df['price'] = df['base_price'] \* (1 - df['age'] / 20)  # 车龄增加,价格降低(每年贬值约5%)* (1 - np.log1p(df['mileage']) / 20)  # 里程增加,价格降低(对数衰减,符合真实折旧)* (1 + df['engine_size'] / 10)  # 发动机越大,价格越高* (1 + df['horsepower'] / 500)  # 马力越大,价格越高* (1 + (df['fuel_type'] == 'electric')*0.2 + (df['fuel_type'] == 'hybrid')*0.1)  # 电动车加价20%,混动车加价10%* (1 + (df['transmission'] == 'automatic')*0.1)  # 自动挡加价10%* (1 + (df['maintenance_rating'] - 5)/50)  # 保养评分每高1分,价格高2%* (1 - df['accident_count']*0.1)  # 每发生一次事故,价格降10%# 添加随机噪声(模拟市场波动)
    df['price'] = df['price'] * np.random.normal(1, 0.1, size=n_samples)  # 10%以内的随机波动
    1.3 价格生成逻辑(核心)
    # 基础价格(按品牌档次)
    brand_base_price = {brand: 50000 for brand in brands['luxury']}  # 豪华品牌基础价5万
    brand_base_price.update({brand: 30000 for brand in brands['mid_range']})  # 中端3万
    brand_base_price.update({brand: 15000 for brand in brands['economy']})  # 经济1.5万
    df['base_price'] = df['brand'].map(brand_base_price)# 价格调整因素(核心逻辑)
    df['price'] = df['base_price'] \* (1 - df['age'] / 20)  # 车龄增加,价格降低(每年贬值约5%)* (1 - np.log1p(df['mileage']) / 20)  # 里程增加,价格降低(对数衰减,符合真实折旧)* (1 + df['engine_size'] / 10)  # 发动机越大,价格越高* (1 + df['horsepower'] / 500)  # 马力越大,价格越高* (1 + (df['fuel_type'] == 'electric')*0.2 + (df['fuel_type'] == 'hybrid')*0.1)  # 电动车加价20%,混动车加价10%* (1 + (df['transmission'] == 'automatic')*0.1)  # 自动挡加价10%* (1 + (df['maintenance_rating'] - 5)/50)  # 保养评分每高1分,价格高2%* (1 - df['accident_count']*0.1)  # 每发生一次事故,价格降10%# 添加随机噪声(模拟市场波动)
    df['price'] = df['price'] * np.random.normal(1, 0.1, size=n_samples)  # 10%以内的随机波动

  • 调整逻辑符合常识:车龄 / 里程越高,价格越低;配置越好(如自动挡、电动车),价格越高。
  • 1.4 缺失值模拟
    # 5%的里程数缺失,3%的保养评分缺失
    df.loc[np.random.choice(df.index, int(n_samples*0.05)), 'mileage'] = np.nan
    df.loc[np.random.choice(df.index, int(n_samples*0.03)), 'maintenance_rating'] = np.nan

  • 模拟真实数据中的缺失情况,为后续预处理做准备。
  • 2. 数据预处理

    预处理是将原始数据转换为模型可输入的格式,包括缺失值处理、分类变量编码等。

    2.1 缺失值处理
    # 用中位数填充缺失值(比均值更稳健,不受极端值影响)
    car_data['mileage'] = car_data['mileage'].fillna(car_data['mileage'].median())
    car_data['maintenance_rating'] = car_data['maintenance_rating'].fillna(car_data['maintenance_rating'].median())

  • 选择中位数填充:因为里程数等特征可能存在极端值(如少数车辆里程极高),中位数更能代表 “典型值”。
2.2 分类变量编码

机器学习模型只能处理数值型特征,需将分类变量转换为数字:

# 1. 品牌档次编码(有序分类:豪华>中端>经济)
brand_category = {}
for cat, brands_list in brands.items():for brand in brands_list:brand_category[brand] = 2 if cat == 'luxury' else 1 if cat == 'mid_range' else 0
car_data['brand_category'] = car_data['brand'].map(brand_category)  # 豪华=2,中端=1,经济=0# 2. 燃油类型独热编码(无序分类:无大小关系)
fuel_dummies = pd.get_dummies(car_data['fuel_type'], prefix='fuel', drop_first=True)
# 生成fuel_diesel, fuel_hybrid, fuel_electric三列(参考类别为gasoline)
car_data = pd.concat([car_data, fuel_dummies], axis=1)# 3. 变速箱类型二值化(自动=1,手动=0)
car_data['transmission'] = (car_data['transmission'] == 'automatic').astype(int)
  • 有序分类(如品牌档次)用数值编码,保留 “高低” 关系;
  • 无序分类(如燃油类型)用独热编码,避免模型误解 “数值大小”(如不认为 diesel=1 比 gasoline=0 高级)。
2.3 特征与目标变量分离
X = car_data.drop(['price', 'brand', 'fuel_type'], axis=1)  # 特征变量(删除价格和无用原始分类列)
y = car_data['price']  # 目标变量(预测的汽车价格)
3. 探索性数据分析(EDA)

通过可视化理解数据分布和特征关系,为建模提供依据。

3.1 价格分布
sns.histplot(car_data['price'], kde=True)  # 直方图+核密度曲线
  • 作用:观察价格的整体分布(是否正态、有无极端值),本例中价格呈多峰分布(因品牌档次不同)。
3.2 相关性分析
correlation = car_data.select_dtypes(include=[np.number]).corr()  # 计算数值特征的相关系数
sns.heatmap(correlation, annot=True, cmap='coolwarm')  # 热力图可视化

  • 作用:查看特征与价格的相关性强度(如品牌档次与价格正相关,车龄与价格负相关),验证特征设计的合理性。
3.3 关键特征与价格关系
sns.scatterplot(x='age', y='price', data=car_data)  # 车龄与价格的散点图
  • 作用:直观观察单个特征与价格的关系(如车龄增加,价格明显下降)。
4. 模型训练与评估

使用决策树回归器构建预测模型,并评估其性能。

4.1 数据集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
  • 将数据按 7:3 分为训练集(用于模型训练)和测试集(用于评估泛化能力)。
4.2 基础模型训练与评估
dt_reg = DecisionTreeRegressor(random_state=42)  # 初始化决策树回归器
dt_reg.fit(X_train, y_train)  # 训练模型
y_pred = dt_reg.predict(X_test)  # 预测测试集# 评估指标
mse = mean_squared_error(y_test, y_pred)  # 均方误差(衡量预测值与真实值的平均平方差)
rmse = np.sqrt(mse)  # 均方根误差(还原为价格单位,更易解释)
r2 = r2_score(y_test, y_pred)  # 决定系数(0-1,越接近1说明模型解释力越强)
  • 基础模型性能:R²≈0.82,说明模型能解释 82% 的价格变异,初步效果较好。
4.3 交叉验证
cv_scores = cross_val_score(dt_reg, X, y, cv=10, scoring='r2')  # 10折交叉验证
  • 作用:避免单次划分的偶然性,更稳健地评估模型性能(本例平均R²≈0.80)。
5. 模型调优(网格搜索)

决策树容易过拟合,通过网格搜索寻找最优参数:

param_grid = {'max_depth': [None, 5, 10, 15, 20],  # 树的最大深度(控制复杂度,避免过拟合)'min_samples_split': [2, 5, 10, 20],  # 分裂节点所需的最小样本数'min_samples_leaf': [1, 2, 5, 10],  # 叶子节点的最小样本数'max_features': ['auto', 'sqrt', 'log2'],  # 每次分裂考虑的特征数量'splitter': ['best', 'random']  # 特征分裂策略
}grid_search = GridSearchCV(estimator=DecisionTreeRegressor(random_state=42),param_grid=param_grid,cv=10,  # 10折交叉验证scoring='r2',  # 优化目标:最大化R²n_jobs=-1  # 利用所有CPU核心加速
)
grid_search.fit(X_train, y_train)  # 执行网格搜索
  • 原理:遍历所有参数组合,选择交叉验证性能最好的参数(grid_search.best_params_)。
  • 效果:优化后模型R²提升至≈0.88,预测精度显著提高。
6. 特征重要性分析

决策树的优势之一是可解释性,通过特征重要性判断哪些因素对价格影响最大:

feature_importance = best_model.feature_importances_  # 每个特征的重要性得分(总和=1)
importance_df = pd.DataFrame({'特征': X.columns, '重要性': feature_importance}).sort_values('重要性', ascending=False)
  • 结果解读:品牌档次(≈35%)、车龄(≈25%)、里程数(≈15%)是影响价格的三大核心因素,与常识一致。

三、核心技术点总结

  1. 模拟数据生成:通过合理的概率分布和业务逻辑,生成贴近真实的数据集,解决数据获取难题。
  2. 数据预处理:针对分类变量选择合适的编码方式(有序编码 / 独热编码),用中位数填充缺失值。
  3. 模型选择:决策树回归器适合处理非线性关系,且结果可解释。
  4. 参数调优:网格搜索自动寻找最优参数,平衡模型复杂度和泛化能力。
  5. 结果解释:通过特征重要性分析,将模型结果转化为可理解的业务洞察。
http://www.lryc.cn/news/626244.html

相关文章:

  • 中科米堆CASAIM自动化三维测量设备测量汽车壳体直径尺寸
  • 浅看架构理论(二)
  • 【habitat学习二】Habitat-Lab 快速入门指南(Quickstart)详解
  • python每日学习14:pandas库的用法
  • MySQL 从入门到精通 11:触发器
  • noetic版本/ubuntu20 通过moveit控制真实机械臂
  • 基于单片机智能手环/健康手环/老人健康监测
  • Kubernetes 的 YAML 配置文件-apiVersion
  • 【AI】算法环境-显卡、GPU、Cuda、NVCC和cuDNN的区别与联系
  • Redis-缓存-击穿-分布式锁
  • ZooKeeper 一致性模型解析:线性一致性与顺序一致性的平衡
  • ISIS高级特性
  • Linux下编译ARPACK
  • 基于提示词工程和MCP构建垂直Agent应用
  • 《P1550 [USACO08OCT] Watering Hole G》
  • Apache Doris 4.0 AI 能力揭秘(一):AI 函数之 LLM 函数介绍
  • uniapp 5+App项目,在android studio模拟器上运行调试
  • 大数据数据库 —— 初见loTDB
  • STM32 vscode 环境, 官方插件
  • 【PyTorch】多对象分割项目
  • 算法训练营day56 图论⑥ 108. 109.冗余连接系列
  • 权重、偏置、运行均值、运行方差的概念
  • sfc_os!SfcValidateDLL函数分析之SfcGetValidationData
  • 2025年09月计算机二级Java选择题每日一练——第一期
  • 瑞萨e2studio:HardwareDebug配置项详解
  • MongoDB知识速查
  • React 静态站点生成
  • 数据结构代码分享-5 链式栈
  • Consul- acl机制!
  • latex|算法algorithm宏包和注意事项