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

一、整体流程概览

这份代码实现了一个完整的机器学习预测流程,核心目标是通过汽车的各项特征预测其价格。整体流程分为 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.pswp.cn/pingmian/93738.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/93738.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

0基础安卓逆向原理与实践:第2章:编程基础与工具链

第2章:编程基础与工具链 2.1 Java编程基础 2.1.1 Java语言特性 Java是安卓应用开发的主要语言,具有以下核心特性: mindmaproot((Java特性))面向对象封装继承多态抽象平台无关字节码JVM一次编译到处运行内存管理自动垃圾回收堆栈管理引用类型安全性字节码验证安全管理器访…

深入理解JVM内存结构:从字节码执行到垃圾回收的全景解析

🧠 深入理解JVM内存结构:从字节码执行到垃圾回收的全景解析 #JVM内存模型 #Java性能优化 #垃圾回收机制 #并发编程一、JVM内存结构全景图二、线程共享区域详解 2.1 堆(Heap)—— 对象生存的宇宙 存储内容: 所有new创建…

用 C++ 构建高性能测试框架:从原型到生产实战指南

用 C 构建高性能测试框架:从原型到生产实战指南 ​C 测试框架的关键价值​:当你的测试需要每秒处理百万级交易,微秒级延迟要求已成为常态时,Python GC 的暂停便是不可接受的奢侈。 本文将深入探讨如何用 C 构建兼具灵活性和高性能…

【C语言16天强化训练】从基础入门到进阶:Day 4

🔥个人主页:艾莉丝努力练剑 ❄专栏传送门:《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、洛谷刷题、C/C基础知识知识强化补充、C/C干货分享&学习过程记录 🍉学习方向:C/C方向 ⭐️人…

C语言:字符函数与字符串函数(1)

在编程的过程中,我们经常会遇到需要处理字符和字符串的情况,为了方便操作字符和字符串,C语言标准库中提供了一系列库函数,接下来我们就学习一下这些函数。 目录 1. 字符分类函数 2. 字母转换函数 3. strlen函数的使用和模拟实现…

数据结构与算法系列(大白话模式)小学生起点(一)

出身,并不重要 !!!!只要有恒心,有毅力,肯于付出与学习,皆会取得相应的成就!天道酬勤,天行健,君子当自强不息!道可道,非常道…

计算机视觉第一课opencv(二)保姆级教学

目录 简介 一、边界填充 1.函数说明 2.案例分析 二、图像运算 1.号运算 2.cv2.add()函数 3.图像加权运算 三、阈值处理 四、图像平滑处理 1.椒盐噪声 2.均值滤波(Mean Filtering) 3.方框滤波 4. 高斯滤波(Gaussian Filtering&am…

DINOv3

一、摘要 https://arxiv.org/pdf/2508.10104 自监督学习有望消除对人工数据标注的需求,使模型能够轻松扩展到大规模数据集和更大规模的架构。由于不针对特定任务或领域进行定制,这种训练范式具有从各种来源学习视觉表示的潜力,能够使用单一…

​​pytest+yaml+allure接口自动化测试框架

高薪必备!18K接口自动化测试框架落地全流程|零基础到实战通关前言# 自动化测试,是目前测试行业一项比较普遍的测试技术了,之前的以UI自动化测试为主,现在的以接口自动化测试为主,无论技术更迭,…

LeetCode每日一题,2025-8-20

统计全为1的正方形子矩阵 这题是正方形,比较简单 暴力就是二维前缀和。 或者用dp,dp[i][j]表示以i,j为右下角的最大正方形的边长,它由(i-1,j),(i,j-1),(i-1,j-1)三者共同决定,通过找规律可知,由三个的最小值…

在Excel启动时直接打开多个Excel文件

如果我们这段时间每天都要打开几个相同的Excel文件开展工作,可以把这几个文件放到一个文件夹(如果原来就在不同的文件夹,就把快捷方式放到同一个文件夹),然后在Excel选项中设置启动时打开这个文件夹中的文件即可。注&a…

对象存储 COS 端到端质量系列 —— 终端网络诊断工具

背景 在COS终端SDK的众多功能中,文件上传功能的使用颇为频繁。鉴于此,提升文件上传的成功率便显得至关重要。众多导致上传失败的因素里,由网络问题引发的故障无疑是其中影响上传成功率的关键因素之一,同时也是最难以把控的要素。…

Flask高效数据库操作指南

Flask-SQLAlchemy 数据库操作关于Flask数据库Flask中没有指定使用的数据库,可以自由选择不管你是使用关系型数据库,还是非关系型数据库都可以,不像django提供了orm 数据库抽象层,可以直接采用对象的方式操作数据库。但是为了开发效…

Camera相机人脸识别系列专题分析之十九:MTK ISP6S平台FDNode原生代码

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、问题背景 二、MTK ISP6S平台FDNodeImp.cpp 2.1:原生代码

S32K3 的图形化配置和EB配置mcal差异

32K3系列的图形化配置工具(如S32 Design Studio, S32DS)与EB配置工具(基于EB tresos Studio)在配置MCAL(Microcontroller Abstraction Layer)时存在关键差异,主要体现在工具环境、配置流程、代码…

Meta 再次重组人工智能部门

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

在nodejs中 有哪些是 “假值“和怎么写 “双重否定”

1.在 Node.js(以及 JavaScript)中,以下值在布尔上下文(例如 if 语句、while 循环条件等)中被视为 “假值”:false:布尔类型的 false 值,这是最直接的假值。if (false) {console.log(…

车载软件架构 --- 赢得汽车软件开发竞赛

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

机器学习总复习

这段时间学习了 KNN,线性回归,逻辑回归,贝叶斯,聚类(K-means,DBSCAN),决策树,集成学习(随机森林,XGboost),SVM支持向量机,…

深入解析EventPoller:Disruptor的轮询式事件处理机制

EventPoller 是什么?EventPoller 是 Disruptor 框架中一种 基于轮询(poll-based) 的事件消费机制。它与我们更常见的 BatchEventProcessor(基于独立的消费者线程)形成了对比。核心区别在于:BatchEventProce…