☰
电动汽车电池数据实战:pandas清洗、聚合分析与避坑指南
2026/10/1 2:40:56 网站建设 项目流程

简介:这份电动汽车数据集收录了2025年3K+条真实车辆记录,覆盖特斯拉、宝马、日产等品牌,包含电池化学成分、容量、续航里程、充电标准与速度、价格、产地、自动驾驶等级、安全评级、销量与保修年限等技术规格和销售属性。每行由Vehicle_ID唯一标识,适合做车型对比分析、市场趋势研究或机器学习建模训练。数据以2025年最新销售数据为时间锚点,并横向涵盖纯电与插电式混合动力车型,可支撑从入门数据清洗到进阶特征工程的完整练习。资源包共3个文件,含xlsx表格便于筛选透视、csv方便程序读取、json适合接口化调用,整包仅492KB,轻量易下载。目前已有203人学习,对于需要真实车市数据完成课程设计或数据可视化项目的学习者来说,是一份紧凑且字段丰富的实用样本。

1. 拿到真实汽车数据后的第一件事:先搞清它到底能干嘛

拿到一份电动汽车数据集时,我第一反应不是看有多少条记录,而是先确认这些记录是从哪来的。2025 年的 3K+ 真实记录,覆盖特斯拉、宝马、日产三个品牌的电池规格与销售数据,意味着你可以直接做三件事:按品牌拆电池容量分布、算单位 kWh 的定价基线、拉出 2025 年逐月销售斜率。它适合的人群很具体——做车载电池成本测算的工程师、写新能源汽车行研报告的运营、准备用真实数据训练分类模型的算法岗。我会按数据字段逻辑、pandas 清洗、聚合分析、踩坑清单、进阶验证这条线往下拆,新手能照步骤跑,熟手可以直接跳到第 4 章对照坑点。

2. 电动汽车数据集的字段逻辑:电池规格与车型配置怎么对应

拿到任何电动汽车数据集,第一件事不是急着画图,而是把字段之间的对应关系摸清楚。以标题里提到的特斯拉、宝马、日产为例,这三个品牌的电池规格记录方式差异非常大,直接决定了后面清洗脚本怎么写。我一般会先把一张表拆成三类信息来看:电池参数、车型身份、销售事件。这三类信息在原始 CSV 里可能挤在同一行,也可能分散在多张表里,但最终都要落到一张可分析的宽表上。

2.1 电池容量、标称电压与续航:三个字段别混着算

电池规格字段是所有分析的地基,但也是单位最不统一的几个字段。常见记录里会有电池容量、标称电压、电池类型和续航里程,其中电池容量大多写着 kWh,但总有一批记录给你的是 Ah,甚至直接写成“60KWH”这种带单位字符串。标称电压决定 Ah 怎么换算成 kWh,公式很简单:kWh = Ah × V / 1000。同一块电池包,350V 平台和 400V 平台换算出的结果能差 14%,所以看到 Ah 必须找同行的电压字段,找不到就标缺失,不要自己假设一个 400V 往里代。

续航字段更不能和容量混着看。LFP 磷酸铁锂和三元锂的放电特性不同,同样 60kWh 容量,放在 Model 3 和放在 Nissan Leaf 上,续航能差出 100 多公里。整备质量、风阻系数、BMS 放电策略都会影响这个数字。做分析时如果想从容量估算续航,应按品牌和车型细分组单独拟合,不要做全局回归,全局回归的结果只能用来定性,不能用来定量。

下面我把最常见的几个电池相关字段列一下,方便你拿到数据后先对一遍字段名,因为数据集来源不同,列名经常叫 battery_capacity_kwh、capacity、pack_size,但含义都是电池包总能量。

字段常见单位典型取值坑点
电池容量kWh / Ah40-100 kWhAh 需乘标称电压换算,部分记录带单位字符串
标称电压V350-800 V老车型 350V,新平台 800V,换算时必须配套
电池类型枚举NCM / LFP缩写混写,如 NMC、磷酸铁锂、LiFePO4 是同一种
续航里程km / mi200-600 km标注标准不统一,CLTC、EPA、WLTP 数字差异明显
电池包版本字符串Standard / Long Range同一车型多个版本,是关联销售数据的关键键

2.2 车型、电池版本与销售记录怎么串成一张宽表

数据商提供的文件我见过两种形态,一种是一张宽表,每行是一台车,电池规格、价格、销售日期都在同一行;另一种是拆成两张表,一张车型规格表、一张销售流水表。后一种更常见,因为电池规格是静态信息,销售流水是动态信息,分开存储更合理。你把两张表合并时,关联键不能只用车系名,必须用车型年款加电池包版本。

举例说,Model 3 在 2024 款里同时有标准版和长续航版,一个 60kWh 磷酸铁锂,一个 78kWh 三元锂,价格差接近一万美元。如果你只按 model_name 去关联销售表,系统会把所有 Model 3 的销售记录都匹配到同一个电池版本上,后面算价格基线的时候整个分布都会拉宽,中位数失真,画出来的箱线图里会出现一大堆本不该存在的离群点。正确的做法是建一个复合键:brand + model_year + battery_version,确保每条销售记录都对应到唯一一份电池配置。

合并完成后,我建议把宽表整理成固定的列顺序,方便后续脚本复用。列结构大致是:vin(车辆识别码)、品牌、车型名、年款、电池版本、电池容量(标准化后)、标称电压、电池类型、续航里程、价格、销售日期。注意销售日期粒度,很多记录只给到年月,没有具体日,这种情况下不要硬填 1 号,直接在分析里按字符串截取前 7 位转成月度周期,反而更干净。这一步做完,你手里才真正有一份能直接进 pandas 做统计的数据。

3. 用 pandas 跑通 3K+ 记录的最小分析流程:从体检到品牌对比

数据表结构确认后,下一步是用 pandas 在本地把整个分析流程跑通。我一般按四个步骤走:读入与体检、字段标准化、品牌聚合、时间序列拆解。这套流程不挑数据集,你以后拿到别的车型数据也能复用。

3.1 先做数据体检:空值、重复值与单位不统一

拿到 CSV 后第一个动作永远是看形状和缺失比例,而不是急着画图。3K+ 记录规模不大,pandas 全量读入内存没问题,但空值分布直接影响后续填充策略。下面这段代码先把基础信息打出来:

import pandas as pd df = pd.read_csv('ev_data_2025.csv', encoding='utf-8-sig') print(df.shape) print(df.dtypes.value_counts()) print(df.isna().mean().sort_values(ascending=False))

这段代码里我特意用了 utf-8-sig 而不是默认编码,因为汽车数据集的 CSV 很多来自国外数据商,带上 BOM 头容易让第一列列名多一个不可见字符。df.isna().mean()输出的是每一列缺失值的占比,比isna().sum()更好用,因为可以直接按比例判断处理策略。我自己的经验阈值是:缺失低于 1% 的列直接按行删;缺失在 20% 到 30% 之间,做成布尔标记列或中位数填充;超过 30% 的列基本不要依赖它做结论。

单位不统一的处理是体检完之后的重点。假设原始表里 battery_capacity 列有数值、有字符串,既有 kWh 又有 Ah,我一般写一个标准化函数:

def normalize_capacity(value, voltage=None): if pd.isna(value): return pd.NA text = str(value).strip().upper() if 'KWH' in text: return float(text.replace('KWH', '')) if 'AH' in text: if voltage is None or pd.isna(voltage): return pd.NA return float(text.replace('AH', '')) * float(voltage) / 1000.0 return float(text) df['capacity_kwh'] = [ normalize_capacity(v, vol) for v, vol in zip(df['battery_capacity'], df['nominal_voltage_v']) ]

这里我用了列表推导式而不是apply,因为需要同时访问两列的值,apply写起来反而绕。Ah 分支下如果拿不到对应电压,直接返回pd.NA而不是猜一个典型电压,这是血泪经验。你一旦填了个假定电压,后面所有按容量做的分组统计都会带着这个系统性偏差,而且极难排查。另一个提示:数据里可能把 7.5KWh 误写成 75KWh,肉眼很难发现。我在做完标准化后一定会按品牌看容量中位数,如果某个品牌的中位数值明显超出同车型常识范围,就回去翻原始记录。

3.2 按品牌聚合电池参数:用中位数建基线

字段标准化之后,最先能出结论的就是品牌维度的电池容量分布。这里的关键选择是用中位数而不是均值。特斯拉车系里高性能版和长续航版的容量明显偏高,少数几台车就能把均值拉上去,而中位数代表大多数用户实际买到的配置水平。代码很简单:

brand_stats = df.groupby('brand')['capacity_kwh'].agg( count='count', median='median', mean='mean', std='std' ) print(brand_stats.sort_values('median', ascending=False))

agg里同时算四个统计量,count 用来判断样本量是否足够,median 做主结论,mean 和 std 辅助看离散程度。做完数值统计后我会顺手画一个箱线图,比表格更直观:

import matplotlib.pyplot as plt brand_order = ['tesla', 'bmw', 'nissan'] box_data = [ df.loc[df['brand'] == b, 'capacity_kwh'].dropna() for b in brand_order ] plt.boxplot(box_data, tick_labels=['Tesla', 'BMW', 'Nissan']) plt.ylabel('Battery capacity (kWh)') plt.show()

箱线图能一次性暴露三类问题:品牌间中位数差异、品牌内部离散程度、异常值。以这类数据集的经验看,Nissan 的容量中位数通常明显低于特斯拉和宝马,因为主力车型 Leaf 定位入门;如果结果完全反过来,第一反应应该是回到数据检查品牌映射是不是把车型分配错了。箱线图也能顺带验证 3.1 里单位换算有没有漏网之鱼——如果某个品牌的容量出现一个孤立的高位点,多半是混入了一条没做 Ah 换算的记录。

3.3 拆出 2025 年销售时间序列:看斜率而不是看总量

销售数据的分析重点不是总量,而是随时间的变化趋势。2025 年逐月销售数据,最常见的处理是把日期归一到自然月,然后按品牌聚合每月交付或销售笔数:

df['month'] = pd.to_datetime(df['sale_date']).dt.to_period('M') monthly = df.groupby(['brand', 'month']).size().unstack('brand', fill_value=0) print(monthly) smoothed = monthly.rolling(3, min_periods=1, axis=0).mean() print(smoothed.tail())

dt.to_period('M')会把日期统一成月份周期对象,避免同一天多笔交付造成的日粒度毛刺。unstack('brand', fill_value=0)把每个品牌变成一列,fill_value=0保证没有记录的月份补零,否则后面绘图时会出现断线。rolling(3, min_periods=1)做三个月移动平均,单月促销带来的销量尖峰会被抹掉,更适合看中期趋势。

注意:如果原表里 sale_date 不是日期类型而是字符串,pd.to_datetime会自动解析,但如果只有年月没有日,解析出来的日期会统一落到当月 1 号,这不影响月度聚合结果。

看趋势不能只靠肉眼,最好算一个数值。拿特斯拉为例,想确认它 2025 年是否在放量,可以用一阶拟合直接得出每月增量:

import numpy as np x = np.arange(monthly.shape[0]) slope_tesla = np.polyfit(x, monthly['tesla'].values, 1)[0] print(f'Tesla monthly increase: {slope_tesla:.1f}')

polyfit的返回值里,第一个元素就是线性拟合的斜率,单位是“辆/月”。这个数字比“特斯拉销量高”这种描述有用得多,因为它可以直接横向对比宝马和日产,谁在放量、谁在收缩一目了然。做这一步时要注意样本月份不能太少,如果只有三个月数据,拟合出的斜率几乎没有参考价值,至少要六个月以上再下结论。

4. 避坑排查:真实汽车数据的五个常见坑,现象与原因

数据集标题里写着“真实数据”,不代表拿到的表是干净的。恰恰相反,真实数据最常见的状态是:每列都填了值,但填进去的内容口径混乱。这一章我把做汽车数据集处理时遇到的高频问题整理成五条,每条都按现象、原因、解决三个层次写,你在复现时可以直接对照。

4.1 车型年款对不上记录年份,聚合结果整体偏移

现象:按 model_year 字段做分组统计,发现 2026 款车型在 2025 年的销售记录里出现不少,价格还明显偏高,年款维度的整体分布向未来偏移。

原因:汽车行业年款发布时间比日历年份提前。2025 年 8 月就上市 2026 款是常规操作,销售表里记录的是实际交易时间,车型表里存的是年款标识,两个时间概念错位。如果把销售记录按 model_year 归组,等于把 2025 年下半年的销量算进 2026 年,趋势分析直接失真。

解决:把两个字段拆开使用,销售分析固定用 sale_year,配置分析才用 model_year。在清洗阶段加一列df['sale_year'] = df['sale_date'].dt.year,所有按时间聚合的逻辑都指向它。年款字段只用来关联车型配置,不进时间维度。

4.2 电池容量混用总容量与可用容量,续航估算直接翻车

现象:某一品牌电池容量中位数比官方标称值低 6% 到 8%,品牌对比图整体下移,用容量推算续航的结果系统性偏低。

原因:数据源里一部分记录填的是电池包总容量,一部分填的是可用容量。动力电池出厂时为了防止过充过放,BMS 会锁住一部分电量,可用容量通常比总容量少 5% 到 10%。不同数据商采集口径不统一,导致同一车型出现两个容量簇。

解决:对每个品牌做容量分布的聚类检查,如果同一车型的容量值形成两个相差超过 5% 的簇,基本就是口径混用。不要统一乘系数,因为你不知道哪条记录是哪种口径。正确做法是按 vin 前缀或电池包代次拆分,看是否对应不同生产批次;分不清时只做品牌间相对排序,不做绝对值对比。这个坑在“真实数据”里出现频率极高,而且很难一眼看出,因为你看到的数据本身就是“自洽”的。

4.3 销售记录混入未交付订单,月度曲线虚高

现象:2025 年某个月销量异常冲高,下个月立刻回落到前值一半,移动平均线出现一个不自然的尖峰。

原因:销售表里同时记录了预订订单和已交付订单,经销商录入订单的时间是客户下定时,不是车辆交付时间。还有一些批次记录是经销商为冲量统一录入,整批订单挤在某个月。

解决:先查表里有没有 order_status、delivery_date 这类字段,有就过滤为已交付。如果没有状态字段,用价格分布做辅助判断,正常交付记录价格集中在指导价附近,预订记录往往只有一笔小额订金。仍判断不了就把异常月份标记为待核验,不要直接进趋势模型。做月度时间序列时,任何超出常规波动幅度的点都要先走这个流程,不要急着写进结论。

4.4 品牌名与车型名大小写混写,groupby 把同一车型拆成两行

现象:groupby('brand')之后出现 tesla 和 Tesla 两行,BMW 和 bmw 同时存在,统计结果被拆散。

原因:数据商多批次导入,有的批次字段值全大写,有的批次首字母大写,前端展示看不出来,一到分组聚合就原形毕露。这个问题的隐蔽性在于,shape 看起来正常,缺失值也少,但聚合结果永远对不上。

解决:清洗第一步就做字符串归一化,顺序不能乱。

df['brand'] = df['brand'].astype(str).str.strip().str.lower() df['model_name'] = df['model_name'].astype(str).str.strip().str.lower()

strip()同时去掉首尾空格和全角空格,lower()统一大小写。这一步必须在任何groupby之前执行,不然后面所有分组统计都要返工重跑。车型名同样需要处理,因为不同批次里 “Model 3” 和 “model3” 极容易并存。

4.5 去重只看主键,把同配置不同车当成重复删掉

现象:按 vin 字段去重后记录数减少了几百条,但再做品牌分布统计,发现原本该有的车型数量对不上。

原因:vin 在物理车辆层面唯一,但同一台车被转售、多次登记时,数据商可能在不同时间点各采集了一条。反过来,同一型号配置的两台车拥有不同 vin,它们不是重复。去重规则没有跟着分析目标走,导致有效样本被误删。

解决:先区分两个场景。做配置统计时按 vin 去重,同一 vin 取最新一条记录;做交易流水分析时不去重,每条销售事件都是独立样本。如果同一 vin 出现在不同月份,大概率是转售,保留最近一次交付记录。去重之前先看df.duplicated(subset=['vin', 'sale_date', 'price']).sum(),三个字段同时重复才是真正需要删的数据。

5. 进阶验证:用单位 kWh 价格把数据集用出增量价值

这套数据集的增量价值不只是看销量,而是把你手里电池规格和销售价格两个维度捏合,得到一个业务上真正有用的指标:单位 kWh 价格。做法是把裸车价除以电池容量,得到每度电多少钱,这个数字可以直接用于横向比较品牌间电池成本差异。计算很简单,但验证过程才是重点。

df['price_per_kwh'] = df['price'] / df['capacity_kwh'] baseline = df.groupby('brand')['price_per_kwh'].agg( median='median', q25=lambda x: x.quantile(0.25), q75=lambda x: x.quantile(0.75) ) print(baseline.sort_values('median'))

这里我特意同时算了 25 分位和 75 分位,单位 kWh 价格的离散度能说明定价策略是统一还是混乱。特斯拉同一电池版本价格相对透明,四分位距会收窄;宝马如果混入了不同驱动版本,区间会明显变宽。拿到结果后用留出法验证:随机抽 80% 的记录重算中位数,看剩下 20% 是否落在四分位区间内,如果大量落在区间外,说明分组内还有你没发现的配置混入。

实践里我拿到这种数据集,最后都会和公开信息做一次对拍。找几个官方公布的车型和电池包配置,对比数据集中中位数与公开标称的差值,差异在 5% 以内基本可以认为数据可靠,超过 15% 就先查币种和是否含税,这两个字段是最容易被忽略的。我现在处理汽车数据集的习惯是,先花十分钟做三件事:确认 sale_date 的粒度,归一化品牌大小写,检查容量列有没有 Ah 字段。这三件事做完,后面所有聚合分析都站在稳的地基上,省掉一半返工。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询