ARTICLE DETAIL

资讯详情

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

电动汽车数据集清洗与特征工程:从电池规格到价格预测

电动汽车数据集清洗与特征工程:从电池规格到价格预测 简介这是一份面向数据分析、市场研究及电动汽车行业爱好者的真实电动汽车数据集围绕2025年销售的3K条记录覆盖特斯拉、宝马、日产等品牌的电池规格、续航里程、充电方式、价格、产地、安全等级及销量等属性可用于车型对比、电池技术趋势和价格区间分析。资源打包为zip压缩包共3个文件分别提供xlsx表格便于Excel透视、csv通用格式适合编程建模、json结构适合Web应用集成体积仅492KB数据规整、便于上手。目前已有204人学习下载适合需要快速获取结构化电动车数据的学习者或研究者使用。数据中还包含多个年份、插电混动车型及部分缺失字段使用者可借此练习数据清洗和单位统一也可观察全球主流车企在2025年的产品布局并进一步开展安全评级与续航表现等交叉分析。1. 电动汽车数据集3K真实记录撑得起哪些分析2025年做电动汽车相关的数据项目最不缺的是模型最缺的是一份能直接落地的真实车辆数据。这份电动汽车数据集把特斯拉、宝马、日产的电池规格和2025年销售数据收成了3K条记录覆盖了二手残值评估、电池衰减回归、区域市场价差这些常见的从业场景也是新车价格预测模型能起步的最小样本量。适合正在做新能源行情分析的工程师、准备用真实车辆数据训练价格与续航分类模型、又不想从零写爬虫的团队拿到之后可以直接验证想法、跑通基线不必从抓取和清洗的泥潭里起步。2. 先读懂这批数据电池规格与销售字段到底怎么对齐2.1 电池规格字段要拆开看容量、电压、测试标准各说各话拿到这个数据集先别急着做特征工程先把“电池规格”四个字拆开。真实来源往往是官网参数表、论坛、第三方数据库混在一起字段叫法很乱。我一般会强制要求至少保留五列电池类型三元锂/磷酸铁锂、标称总容量kWh、可用容量kWh、标称电压V、续航里程km。缺任何一个后面换算都容易出问题。这里有个特别容易翻车的地方同一款车NEDC、WLTP、EPA三种测试标准测出来的续航差距很大。欧洲2020年前的车喜欢标NEDC美国车标EPA中方厂商不少拿CLTC。比如特斯拉Model 3长续航EPA大约在570-600km换WLTP能到629kmNEDC甚至敢标到668km。所以看到range_km字段时必须同时确认test_std字段否则别直接拿它建续航回归模型。你可以在后续处理里新建一列test_std把“NEDC/WLTP/EPA/CLTC”四个值归一缺掉的置NaN。日产Leaf的电池规格字段尤其要小心。Leaf在官方文档里同时会出现电池包kWh值和电芯Ah值第三方采集员经常把“40Ah电芯”直接当“40kWh电池包”写进去。所幸电池包标称电压通常在同一行里标准的换算公式是kWh 电压(V) × 电流(Ah) / 1000。比如一组标称360V、66Ah的电池包算出来是23.76kWh对应早期24kWh的Leaf而不是66kWh。这个坑在二手欧洲车的规格表里最常见单位不统一一不注意就把整个分布的右尾拉歪。宝马i3也是典型的演进样本。早期i3用60Ah电芯电池包约22kWh中期改款用94Ah约33kWh末期用120Ah约42kWh。三款电池包外观尺寸几乎一样但BMS软件版本、充电功率、可用容量都不一样。如果你只按“BMW i3”去合并销售表必然出错。反过来如果销售表里恰好有电池容量字段你就可以反推它是哪一代电池从而补全年款信息。这就是为什么我坚持把电池容量作为合并主键的一部分而不是辅助信息。2.2 销售数据字段还有一套口径价格、地区、时间销售数据比电池规格更脏。首先是价格同一款Model Y美国、欧洲、中国、东南亚的价格不一样而且有些是含税指导价有些是补贴后地价有些是二手车成交价。要做跨市场对比必须先归一化币种和税务口径。我一般新建price_usd、price_includes_tax两列原始价格字段永远保留不动这是血泪教训改原始列会丢掉下游复盘的依据。时间字段是另一个坑。2025年销售数据不是一个时间点而是月度或季度记录。特斯拉每个季度会对长续航版做临时降价促销宝马i系列经销商折扣甚至能到15%如果按“2025年全年平均价”建模实际是在用一个不存在的价格。正确做法是保留sale_year、sale_month两列把价格当成时变特征别把2025年的12个月合成一列全年均价。很多研究残值的模型会忽略这一点结果就是对促销月的价格预测系统性偏高。字段对齐策略上我的经验是“品牌车型年款”只能做辅助键真正的合并主键要带电池规格。原因很简单Model 3在2021款之后同时卖过标准续航约55-62kWh和长续航约75-82kWh单看车型名销售表里根本分不出来是哪个配置。把电池容量作为主键一部分之后两条数据才能落到同一行。这里还藏着一个多对多问题同一车型同一个容量可能覆盖两个年款所以我的merge_key通常是“品牌_车型_电池容量_年款”。最后建议把字段字典固定下来我倾向于在进模型之前把表格规范成19到20列。这个步骤不复杂但特别重要字段没从一开始统一后面每做一次合并就多一次脏数据。字段字典设计好之后无论原始数据叫“Battery Capacity”还是“电池容量”都映射到同一列后续特征工程和模型验证才不用反复返工。标准字段类型示例说明brandstrtesla厂商统一小写modelstrmodel_3车型归一化yearint2024年款battery_kwh_rawfloat82.0厂商标称总容量battery_kwh_usablefloat79.0BMS可用容量voltagefloat400标称平台电压range_kmfloat629续航必须配test_stdtest_stdstrwltpwltp/epa/nedc/cltcprice_usdfloat42990归一化美元价格price_typestrmsrpmsrp/dealer/used/after_incentivesale_monthint2025032025年3月3. 把3K记录落进本地数据整理与字段标准化的最小流程3.1 先做数据勘察不要跳过shape、dtypes和缺失值拿到数据后第一件事不是读文件内容而是跑一个标准的勘察脚本。很多从报表系统导出的CSV带BOM头Excel打开过再存一次编码和分隔符都会变化所以read_csv要用utf-8-sig并显式声明分隔符。勘察脚本的核心是三件事看形状、看字段类型、看缺失分布。import pandas as pd import numpy as np df pd.read_csv(ev_dataset_2025.csv, encodingutf-8-sig) print(shape:, df.shape) print(columns:, df.columns.tolist()) print(df.dtypes) missing df.isna().sum() print(missing[missing 0]) print(df[brand].value_counts(dropnaFalse))这段代码里df.shape告诉你记录数和字段数是否和标题描述一致如果少了超过10%先怀疑读取问题再怀疑原始文件被截断。df.dtypes是找“数字被读成字符串”的最快路径比如price列是object而不是float64说明里面有逗号或货币符号。最后一行value_counts可以快速看品牌分布是否真的集中在特斯拉、宝马、日产三家。参数说明encodingutf-8-sig是为了吃掉UTF-8 BOM头Windows下导出的CSV几乎都有dropnaFalse能把缺失值单独显示成NaN一行。我习惯在前三步不drop任何行纯粹摸清底数避免在没看清分布的情况下误删数据。3.2 电池规格字段统一成数值型kWh电池规格往往是字符串比如“82 kWh (usable 79 kWh)”“66 Ah 350V”“600 Wh”。一步到位做单位归一化的脚本长这样import re def parse_capacity(text): if pd.isna(text): return np.nan s str(text).lower().replace( , ).replace(,, ) m re.search(r(\d(?:\.\d)?)\s*(kwh|wh|ah), s) if not m: return np.nan val float(m.group(1)) unit m.group(2) if unit wh: return round(val / 1000, 2) if unit kwh: return round(val, 2) vm re.search(r(\d(?:\.\d)?)\s*v, s) if not vm: return np.nan return round(val * float(vm.group(1)) / 1000, 2) df[battery_kwh_parsed] df[battery_spec_raw].apply(parse_capacity)逻辑说明先把字符串里的空格和逗号全部去掉让“82 kWh”变成“82kwh”再用正则优先匹配数字加单位。匹配到Wh就除以1000匹配到Ah则必须在同一字符串里找到电压V否则直接返回NaN。这个设计是故意的Ah没电压就是不可换算的脏数据猜一个值会让后面整个回归都不稳。参数说明正则中的“\d(?:.\d)?”同时覆盖了“82”和“82.1”两种写法“\s*”是保险虽然前面已经去过空格但万一换行符没被replace掉也能兜住。这里有个易错点字符串“79kwh”和“82kwh”可能同时出现在同一行里regex默认只匹配第一处所以我会在解析前先去截最短的数值段或者直接用findall加min避免把“usable 79”当成总容量。提示解析结果出来后直接对比battery_kwh_parsed和原始列的分布。如果原始列有“总容量/可用容量”两种语义务必拆成battery_kwh_raw和battery_kwh_usable两列别混在一个字段里。3.3 2025年销售时间与价格口径清洗时间字段和价格字段是清洗的重头戏。sale_month如果以整数形式存在比如“202501”直接用pd.to_datetime解析如果带中划线“2025-01”就把format参数改掉。价格的脏数据通常是逗号、货币符号、空格混着来。def clean_price(price_str): s str(price_str).replace(,, ).replace($, ).replace( , ).strip() try: return float(s) except ValueError: return np.nan df[sale_month_dt] pd.to_datetime(df[sale_month].astype(str), format%Y%m) df[price_usd] df[price].apply(clean_price)逻辑说明clean_price把美元符号、千分位逗号、中间空格全部去掉后再转float转不动说明原值可能是“约45万”这类非结构化文本直接置NaN比猜一个数更安全。sale_month先转字符串再指定format%Y%m是为了兼容“202501”和“20251”这种Excel把前导零吞掉的情况。参数说明astype(str)是把整型时间列转字符串pd.to_datetime遇到“20251”这种非法格式会报错所以实际项目中我一般加errorscoerce这样解析失败会变成NaT而不是中断流程。价格清洗后一定要再画一次describe()如果price_usd的最小值小于1000基本可以断定单位不是美元而是人民币标价被误判成美元了。4. 多源合并与特征工程让3K记录能喂给模型4.1 合并主键品牌、车型、电池容量三段式现在数据集里有电池规格表、销售表可能还有一份年款配置表。直接按品牌和车型合并一定会撞车因为同一车型在不同年款有不同电池容量。我的做法是构造三段式merge_key。def norm_key(x): s str(x).lower() return re.sub(r[^a-z0-9], _, s).strip(_) df[brand_key] df[brand].map(norm_key) df[model_key] df[model].map(norm_key) df[pack_key] df[battery_kwh_parsed].round(1) df[merge_key] df[brand_key] __ df[model_key] __ df[pack_key].astype(str)逻辑说明norm_key先把“BMW”转成“bmw”把“Model 3”转成“model_3”统一大小写和分隔符。pack_key把容量四舍五入到一位小数兼容“82.0”和“82”因为数据结构不同导致的微小误差。参数说明round(1)并不是万能药如果两份数据一份用总容量、一份用可用容量四舍五入也救不回来必须先靠battery_kwh_raw/usable两列统一到同一种语义再做round。还有一个细节nm口品牌的“i3”会保留数字不会有问题“M3”在特斯拉语境里是Model 3但在宝马语境是M3所以merge_key前面加了brand_key用品牌做第一段隔离。合并时我还会检查merge_key的重复率。正常情况下每个key对应一条记录如果某个key对应多条大概率是两个年款共用同一组电池规格那就必须把year加进merge_key。价差模型里年款这个变量太重要了不能省。4.2 构造可用特征能耗、充电倍率、单位容量价格合并完字段后数据集已经具备进模型的基本形状。但原始字段不适合直接喂给线性模型因为续航、容量、价格之间的量纲差异太大。我会先构造三个解释性强的特征。df[energy_eff] df[range_km] / df[battery_kwh_parsed] # km/kWh df[c_rate] df[fast_charge_kw] / df[battery_kwh_parsed] # 近似充电倍率 df[price_per_kwh] df[price_usd] / df[battery_kwh_parsed]逻辑说明energy_eff是每度电能跑多少公里数值越大越省电国产车通常在6-8km/kWh老款Leaf能到5左右高性能车反而可能低于4。c_rate是最大快充功率除以容量800V平台车型通常能到2C以上400V车型多在1-2C之间这个特征可以帮你快速识别平台电压等级。price_per_kwh是把价格除以容量得到“每度电多少钱”用来横向比较不同容量的定价合理性这在残值分析里是个很敏感的指标。参数说明如果原始数据没有fast_charge_kw字段c_rate这一列就直接不构造不要用快充功率缺失的行硬算。另外价格在不同地区差异很大price_per_kwh最好分地区、分品牌来看不然特斯拉和日产的对比会被汇率和税费政策带偏。做完特征之后我建议再做一轮相关性检查。把energy_eff、c_rate、price_per_kwh、price_usd、battery_kwh_parsed放进corr()如果price_per_kwh和battery_kwh_parsed的相关系数超过0.9说明价格基本由容量决定这个数据集很适合做回归如果相关系数接近0则说明市场定价被品牌和年份主导容量只是辅助变量。3K条记录做相关性检查是秒出的完全跑得动。4.3 切分训练验证按时间切别随机切销售数据天然带时间属性做价格预测时绝对不能把2025年全年混在一起随机切。我见过太多次这种翻车训练集里包含了月底降价记录验证集里出现了月初记录模型指标好得反常一上线就崩。正确做法是排序后按月份切。from sklearn.model_selection import train_test_split df df.sort_values(sale_month_dt) valid df[df[sale_month_dt] 2025-10-01] train df[df[sale_month_dt] 2025-10-01] X_train pd.get_dummies(train[[brand, model, battery_kwh_parsed]], columns[brand, model]) y_train train[price_usd] X_valid pd.get_dummies(valid[[brand, model, battery_kwh_parsed]], columns[brand, model]) X_valid X_valid.reindex(columnsX_train.columns, fill_value0)逻辑说明先把数据按时间升序排好取2025年10月之后做验证集之前做训练集。get_dummies把品牌和车型展开成哑变量这样特斯拉、宝马、日产的品牌效应会被模型显式学习。X_valid reindex到X_train的列集是为了防止验证集里出现训练集没有见到的新车型导致报错。参数说明10月这个切分点你可以按数据量调整一般是最后2-3个月做验证。stratify只在随机切分时有意义时间切分没有必要加。如果你要预测的是“未来价格”那么训练集里绝不能出现晚于验证集日期的任何记录哪怕那些记录价格更“正确”。时序泄漏是所有销售数据建模里最隐蔽的问题四舍五入的merge_key坑是数据质量时间顺序坑是方法论两个都要单独检查。5. 实名避坑整理这类电动车数据集最容易翻车的五个细节5.1 电池容量单位混用现象battery_spec_raw里同时出现“66 Ah”“58 kWh”“600 Wh”一个字段三项三种单位。原因数据源混合了电芯参数、电池包参数和第三方二手网站的自定义字段。欧洲二手车网站偏爱Ah国内网站几乎清一色kWh抓取合并时没人统一。解决先按3.2里的parse_capacity统一到kWh。Ah必须带电压换算如果同一行里找不到电压字段直接置NaN不要用同车型中位数去填Ah类缺失。单位混用的数据一旦混进训练集容量特征会平白多出几倍的噪声。5.2 总容量与可用容量被当成一列现象同一车型两个来源一个标82kWh一个标79kWh两个都对。原因厂商对外宣传往往标电池包总容量BMS系统实际可用的部分会锁掉3-5kWh。不同数据源一个抓官网总容量一个抓车主App里的可用容量。解决先建battery_kwh_raw和battery_kwh_usable两列。做残值分析和续航预测全用usable因为价格和续航是由用户可用的电量决定的做充电时间粗算和能耗标称对比才用raw。建模前在数据字典里写明你用哪一列否则模型系数没有可解释性。5.3 2025年销售价格口径不一致现象同样一台Model Y一条记录42990美元另一条折合下来38900美元。原因前者是含税落地价后者是不含税裸车指导价更隐蔽的是有人把“补贴后价格”混了进来导致同配置同时间出现两个相差悬殊的价位。解决增加price_type列值域设为msrp/dealer/used/after_incentive并在建模时只保留其中一种。做新车价格分析用msrp做二手车残值用used千万不要混着训练。这个过程靠脚本检查可能发现不了得直接看同一merge_key下的价格极差大于15%就要手工核对。5.4 电池规格缺失率过高现象3K条记录里20%的电池容量为空直接drop后长续航、高配车型被删掉一大半样本分布完全偏移。原因老款Leaf和宝马i3早期发布时官方参数不完整第三方数据源不采集电池规格越老的车型缺失越严重。解决先用官方配置表做一次补全剩下的按brandmodelyear分组取中位数插补同时加is_imputed标记列。中位数计算时要先剔除本组内的NaN行如果一组全是NaN就别硬补直接保留缺失并交给树模型处理。5.5 时序泄漏现象价格模型在验证集上R²高得离谱接近0.95一放到真实业务里预测就整体偏移。原因把2025年全年数据混在一起后随机切分训练集包含了月底的降价记录而验证集用了月初的价格模型等于提前看到了“未来”。解决永远按sale_month排序后切分验证集在时间上严格晚于训练集。对销售数据做随机切分的唯一后果就是指标失真没有例外。代码层面可以加一个断言assert valid[sale_month_dt].min() train[sale_month_dt].max()把这条写进流程谁改切分逻辑都会立刻被发现。6. 基线验证用价格-容量回归检验这批数据值不值得投入数据整理完先不要急着上XGBoost或深度学习。我习惯先跑一个价格对容量的简单线性回归这一步能花两分钟告诉你数据质量到底行不行。import statsmodels.api as sm sub df.dropna(subset[price_usd, battery_kwh_parsed]).copy() X sm.add_constant(sub[battery_kwh_parsed]) y sub[price_usd] ols sm.OLS(y, X).fit() print(ols.summary().tables[1])逻辑说明battery_kwh_parsed的系数应当显著为正p值远小于0.05。如果系数为负基本可以断定前面某个环节出了问题最可能是容量单位混用或价格口径不一致。R²在0.2到0.5之间都算正常因为价格还被品牌、年款、地区强烈影响单靠容量解释不了全部。接下来你可以把brand、range_km加进特征再看R²如果从0.3涨到0.7说明数据集的结构是健康的品牌效应被模型成功捕捉。这一版的教训我记忆很深。以前拿到一批“2024纯电车型数据”没有做单位统一直接喂回归容量系数居然为负。排查了两个小时发现约两成容量字段是Ah没换算约三成价格混了汇率。那种翻车最伤的不是数据本身而是时间你永远不知道是代码错了还是市场疯了。从那以后无论数据多急我都先跑一遍这个基线回归R²异常低就直接拦下整个流程不带着脏数据往下走。3K条记录跑这个检查完全够用算下来也就一眨眼的功夫。希望这套整理流程能帮你在自己的数据集上少踩同样的坑。本文还有配套的精品资源点击获取
返回列表