简介:一套针对2024年全电动汽车保有量数据的可视化分析资源,涵盖原始数据集与完整分析代码,适合数据分析初学者、电动汽车行业研究者及市场分析人员快速掌握从数据处理到图表呈现的全流程。压缩包共3个文件,包含csv原始数据(涉及品牌、型号、续航、销量、充电桩分布等维度)、html交互式可视化页面,以及ipynb分析代码,后者完整演示了数据清洗、分类汇总、相关性分析和可视化绘制等步骤。资源仅3.8MB,轻量便捷,已有196人学习。通过运行代码,读者可学习如何从数据中提取市场趋势、用户偏好和充电设施使用效率等关键洞察,并将复杂数据转化为直观图表,是数据可视化课程的理想配套练习,也可作为行业分析报告的实用参考。
1. 2024 年全电动汽车数据集:拿到手先别急着画图
很多做数据分析的人拿到「2024 年全电动汽车数据集」这类压缩包,第一反应是赶紧解压、跑个head()、拖进可视化工具里看效果。结果往往是图还没画出来,就被字段口径问题卡住:续航有的写 km、有的写 miles,价格有的标万元、有的标元,部分车型的销量还是空值。翻车翻得莫名其妙。这个标题真正要解决的事情,是把一份包含品牌、车型、价格、续航、电池容量、销量等字段的全电动汽车数据集,通过 pandas 清洗成可用的结构化数据,再用合适的可视化方案把市场结构讲清楚。它适合两类人:一是刚接触数据分析的从业者,想找一个完整案例练手;二是要做商业数据分析报告,需要快速梳理某个品类竞争格局的人。关键是,可视化只是最后一步,前面八成的工作在数据清洗与口径统一上。这篇笔记就按这个顺序把整条路径拆开讲,每个步骤都给出可直接套用的代码。
2. 先用 pandas 把 rar 里的数据盘明白:字段口径与清洗是可视化的地基
数据分析项目里最容易被低估的就是数据准备阶段。你拿到的是一个 rar 压缩包,里面可能有 CSV、Excel,甚至还有一个说明文档。不要跳过这一步直接画图,字段口径不一致时画出来的每张图都在误导你。
2.1 解压与读入:先看字段长什么样,再谈画图
常见做法是先把 rar 解压到工作目录,然后列出文件清单,确认里面到底有哪几张表。这个动作不要嫌麻烦,它决定了你后续所有代码的路径。
# 在项目目录下解压,并列出文件结构 unrar x 2024全电动汽车数据集.rar -d ./ev_data/ ls -lh ./ev_data/用unrar x解压比双击解压更可控,因为你可以指定解压路径,避免文件散落一地。解压完成后,ls -lh能让你一眼看到文件大小和格式。如果系统没装unrar,用 Python 的rarfile库也能解,但需要本地有unrar可执行文件,所以我在 Linux 环境通常直接装 unrar 工具。
读入数据用 pandas,先只读前几百行做结构预览,不要一次性把全表 load 进来。这一步的目的是快速确认列名、字段类型和大致的数据形态,而不是急着分析。
import pandas as pd # 先预览前 200 行,确认列名和字段类型 df = pd.read_csv("./ev_data/EV_2024.csv", nrows=200) print(df.head()) print(df.dtypes)nrows=200是关键参数,避免读入大文件后才发现分隔符错了、列名跑偏了。df.dtypes会告诉你每个字段的存储类型,后面所有类型修正都以这次预览为基础。
2.2 字段口径统一:续航、价格、销量的单位换算与类型修正
预览之后,最常遇到的脏数据有三类:单位不统一、字符串里混着中文单位、数值字段被识别成 object。比如续航字段写成 “500km”、“300 miles” 混着来;价格字段有的是 “23.98万元”,有的是 “239800元”;销量列里可能有 “1.2万” 这种写法。先把这些全部转换成统一的数值。
import re df["range_km"] = df["range"].apply(lambda x: float(re.sub(r"[a-zA-Z\s]", "", str(x))) * 1.609 if "mile" in str(x) else float(re.sub(r"[a-zA-Z\s]", "", str(x))) ) df["price_wan"] = df["price"].apply(lambda x: float(re.sub(r"[^0-9.]", "", str(x))) / 10000 if "元" in str(x) and "万" not in str(x) else float(re.sub(r"[^0-9.]", "", str(x))) )第一行把带 “mile” 的续航值乘以 1.609 换算成公里;第二行把纯元的价格除以 10000 转成万元。re.sub的作用是剔除汉字和单位字符,只留下数字和小数点。注意,这两步都假设数据里没有缺失值,实际处理时要在apply里加异常捕获或先用pd.to_numeric(errors='coerce')兜底。
做完单位换算,还要检查数值列的类型。pandas 读入时如果某列混入字符串,会被整体识别成 object,此时要手动转换:
df["battery_capacity"] = pd.to_numeric(df["battery_capacity"], errors="coerce") df["sales_2024"] = pd.to_numeric(df["sales_2024"], errors="coerce")errors="coerce"会把无法解析的单元格变成 NaN,宁可先留着空值,也不能让它变成绘图时的隐患。这一步做完后,再输出一遍df.dtypes,确认所有参与计算的列都是 float64 或 int64。
2.3 缺失值与重复值处理:哪些行该删,哪些空得留着
缺失值处理没有固定答案,核心原则是:参与计算的关键字段缺失就删,对分析结论影响小的字段可以填充。价格、续航、销量这三个字段如果缺失,这条记录画进图表里会变成「黑洞」,要么删,要么单独做标记。
df_clean = df.dropna(subset=["price_wan", "range_km", "sales_2024"]) df_clean = df_clean.drop_duplicates(subset=["brand", "model", "version"]) # 看清洗结果 print(df_clean.shape) print(df_clean[["price_wan", "range_km", "sales_2024"]].describe())dropna(subset=...)只检查指定的三个关键字段,其他字段的缺失不影响这条数据的核心价值。drop_duplicates按品牌 + 车型 + 版本号去重,因为同一车型的不同配置可能被重复录入。最后的describe()输出均值、分位数和最大最小值,能快速发现有没有异常值——比如价格出现 0 元、续航出现 10000 公里。发现异常值别急着删,先回到原始数据里确认是不是单位换算时出了问题。
3. 四张图看穿 2024 电动汽车市场:价格、续航、销量与品牌分布
数据清洗完之后,可视化分析才有意义。这章不追求花哨的图表数量,而是用四张图分别回答四个问题:价格带怎么分布、续航和价格是否正相关、哪些品牌卖得好、哪些车型续航最靠前。
3.1 先做分组聚合:用 groupby 把市场切成可解释的块
画图之前先做聚合分析。直接对全表画散点图,数据点叠在一起根本看不出结构。常见的做法是先按品牌分组,看品牌层面的销量集中度;再按价格区间分段,看不同价格带的车型数量。
brand_sales = df_clean.groupby("brand")["sales_2024"].sum().sort_values(ascending=False) price_bins = pd.cut( df_clean["price_wan"], bins=[0, 10, 20, 30, 50, 100], labels=["10万以下", "10-20万", "20-30万", "30-50万", "50万以上"] ) price_dist = df_clean.groupby(price_bins, observed=True)["model"].count()brand_sales计算每个品牌的总销量并降序排列,用来画横幅条形图。pd.cut把价格切成五个档位,observed=True是 pandas 2.x 版本处理分类分组时的必选参数,不加会报警告或得到空分组。price_dist统计每个价格带的车型数量,用来画分布图。这一步的价值在于:聚合结果本身就在回答问题,图表只是把结果可视化。
3.2 四张核心图的选择逻辑:一张图只回答一个问题
初学可视化的人容易犯一个错误:想在一张图里塞进品牌、价格、续航、销量四个维度,结果图是画出来了,什么都没说清楚。我的习惯是一张图只回答一个问题。价格分布用直方图,续航和价格的关系用散点图,品牌销量用条形图,头部车型续航用横向条形图。
import matplotlib.pyplot as plt fig, axes = plt.subplots(2, 2, figsize=(14, 10)) # 第一张:价格分布直方图 axes[0, 0].hist(df_clean["price_wan"], bins=30, color="#4C72B0", edgecolor="white") axes[0, 0].set_title("2024 电动汽车价格分布", fontsize=13) axes[0, 0].set_xlabel("价格(万元)") axes[0, 0].set_ylabel("车型数量") # 第二张:续航-价格散点图 axes[0, 1].scatter(df_clean["range_km"], df_clean["price_wan"], alpha=0.5, s=df_clean["sales_2024"] / 500, c="#55A868") axes[0, 1].set_title("续航与价格关系(气泡大小=销量)", fontsize=13) axes[0, 1].set_xlabel("续航(km)") axes[0, 1].set_ylabel("价格(万元)") # 第三张:品牌销量 top 条形图 brand_sales.head(10).plot(kind="barh", ax=axes[1, 0], color="#C44E52") axes[1, 0].set_title("2024 品牌销量 TOP10", fontsize=13) axes[1, 0].set_xlabel("销量(万辆)") axes[1, 0].invert_yaxis() # 第四张:续航 TOP15 车型 df_clean.sort_values("range_km", ascending=False).head(15).plot( kind="barh", x="model", y="range_km", ax=axes[1, 1], legend=False ) axes[1, 1].set_title("续航 TOP15 车型", fontsize=13) axes[1, 1].set_xlabel("续航(km)") plt.tight_layout() plt.savefig("./ev_analysis/overview.png", dpi=150)散点图的s参数把销量映射成气泡大小,但要注意s的单位是像素面积平方,所以用销量除以 500 做缩放,具体除多少取决于你的销量数量级,需要调。所有图统一用 set_title 加清晰的中文标题,输出分辨率 dpi=150 足够放进报告。tight_layout()这行不能省,否则四个子图的标题和坐标轴标签会互相挤压。
3.3 从图表到结论:价格区间、续航门槛、头部品牌的读数方式
图不是画完就结束的,可视化分析的落点是「你能从图里读出什么结论」。通常在价格分布图上,能看到 10 万到 20 万区间存在一个明显峰值,说明这个价格带竞争最激烈。续航与价格散点图一般呈现出弱正相关——续航 500km 以上的车型集中在 20 万以上区间,但低价位也存在个别长续航车型,这些点值得单独拉出来看,往往代表特定技术路线或品牌定价策略。
品牌销量条形图要结合利润和销量两个维度看。某个品牌销量领先并不等于盈利能力最强,这里只回答「谁的出货量大」。续航 TOP15 的榜单要留意有没有租电池、换电这种特殊商业模式车型混入,它们的价格不含电池,续航数据本身没问题,但放进「以价格换续航」的对比里会误导人。
4. 用 matplotlib 和 pyecharts 做可交互可视化:从静态到 HTML 的落地路径
matplotlib 适合做分析阶段的快速探索,但汇报给业务方时,静态图的说服力远不如一张能悬停看数值、能筛选维度的交互图表。这章从工具选型讲起,落到一张可交付的 HTML 看板。
4.1 静态与交互的选型边界:分析草图用 matplotlib,汇报看板用 pyecharts
选可视化工具有个简单判断标准:你自己看逻辑时用 matplotlib,速度快、参数直观;要给别人看结论时用 pyecharts,生成的 HTML 可以在浏览器里交互,不需要对方装 Python 环境。如果项目需要嵌入 Web 系统,pyecharts 的图表也可以导出为独立的 HTML 文件直接嵌入。
pyecharts 的优势在于 tooltip、缩放、数据刷选这些交互能力是内置的,不需要你手写前端。缺点是配置项多,且默认渲染方式依赖 CDN 加载 JavaScript,离线环境会白屏。这个坑在下一章详细说。对于「2024 全电动汽车数据集」这个项目,我建议静态图做分析,交互图出报告,两条路径并行。
4.2 用 pyecharts 做一张带 tooltip 的价格-续航气泡图
气泡图是展示三维数据(价格、续航、销量)的合适载体,pyecharts 的实现比 matplotlib 更适合做汇报场景。
from pyecharts.charts import Scatter from pyecharts import options as opts # 用清洗后的数据构建图表 scatter = ( Scatter() .add_xaxis(df_clean["price_wan"].tolist()) .add_yaxis( "车型", [ [p, r, s] for p, r, s in zip( df_clean["range_km"].tolist(), df_clean["sales_2024"].tolist(), df_clean["model"].tolist() ) ], symbol_size=8, label_opts=opts.LabelOpts(is_show=False), ) .set_global_opts( title_opts=opts.TitleOpts(title="2024 电动汽车价格-续航分布"), xaxis_opts=opts.AxisOpts(name="价格(万元)", type_="value"), yaxis_opts=opts.AxisOpts(name="续航(km)", type_="value"), tooltip_opts=opts.TooltipOpts( trigger="item", formatter="{b}<br/>价格:{c0} 万元<br/>续航:{c1} km" ), datazoom_opts=[opts.DataZoomOpts(type_="inside")], ) .render("./ev_analysis/price_range_scatter.html") )页面打开后鼠标悬停在气泡上,会显示车型名称、价格和续航。datazoom_opts加了一个滚轮缩放功能,数据点密集时可以放大查看局部区域。formatter里的{b}是系列名,{c0}和{c1}分别对应数据数组里的第一个和第二个值。
4.3 中文字体与颜色映射:让图表不「花」也不「糊」
很多人画完图发现中文变成方框,这是因为 matplotlib 默认字体不支持中文。全局设置两行代码可以解决:
import matplotlib.pyplot as plt plt.rcParams["font.sans-serif"] = ["SimHei", "Arial Unicode MS", "Microsoft YaHei"] plt.rcParams["axes.unicode_minus"] = False第一行指定中文字体,按系统环境选一个存在的字体;第二句关闭减号的 unicode 解析,否则坐标轴上的负号会显示成方块。pyecharts 默认使用浏览器渲染,不存在这个问题,但它在图表配色上容易用力过猛。颜色映射的原则是:分类数据用不同色相,连续数据用渐变,同一个图表里颜色种类不超过五个。我不是说必须用某个固定主题,而是强调「图表的颜色要服务于信息层级」,标签、数据点和辅助线应该各司其职。
5. 数据可视化避坑:这 5 个问题最让新手翻车
这一章写的是真实项目里最容易翻车的地方,每条都是踩过的坑,按「现象 → 原因 → 解决」的顺序呈现。
问题一:条形图横轴变成乱序文本
- 现象:画品牌销量图时,横轴标签不是从大到小或从小到大排列,而是按拼音首字母排,或者出现「万」字这种残留字符。
- 原因:销量字段没有转成纯数值,pandas 按字符串排序;或者单位换算后忘记了
sort_values。 - 解决:确认
sales_2024列已用pd.to_numeric转成数值类型,画图前执行brand_sales.sort_values(ascending=False),并在plot(kind="barh")中加legend=False避免多余图例干扰。
问题二:散点图数据点全部挤在左下角
- 现象:续航-价格散点图上,几千个点全挤在坐标轴左下角,右上角几乎空白,完全看不出趋势。
- 原因:数据量过大且大部分车型集中在低价长续航区间,直接绘制时普通点完全重叠。
- 解决:用
alpha=0.3降低点透明度,同时按价格对数据做分层抽样再用不同颜色区分价格带,这样能在大规模数据中看清楚分布密度差异。如果销售和价格的量级差距过大,可考虑对坐标轴取对数。
问题三:图表下方文字重叠截断
- 现象:品牌销量 TOP10 的横向条形图,最长的品牌名被截掉一半,或者多个标签互相遮挡。
- 原因:默认画布尺寸不够宽,字体大小和标签长度不匹配时 pyplot 不会自动换行。
- 解决:创建画布时指定
figsize=(10, 8),并根据标签长度动态调整字体大小;横向条形图通常比纵向条形图更适合展示中文长标签,因为文字按行排列不会旋转。
问题四:pyecharts 生成的 HTML 打开后空白
- 现象:双击打开 pyecharts 渲染出的 HTML 文件,页面是白屏,只有左上角一个标题,图表区域空白。
- 原因:pyecharts 默认通过 CDN 加载 echarts.min.js,离线或内网环境加载失败,图表就不会渲染。
- 解决:将渲染模式切换为 SVG 或使用本地资源。最简单的方式是在渲染时加一行:
from pyecharts.globals import CurrentConfig CurrentConfig.RENDERER = "svg"或者在部署时把 echarts.min.js 下载到项目目录并配置CurrentConfig.ONLINE_HOST指向本地路径。报告交付前务必在目标环境里打开一次确认。
问题五:价格分布图出现莫名其妙的双峰
- 现象:价格直方图上出现两个相距很远的峰值,比如一个在 10 万附近,一个在 80 万附近,中间断档。
- 原因:没有做单位统一,部分行价格单位是元,部分是万元,混在一起画图产生了两个峰。
- 解决:清洗阶段用第 2 章的换算逻辑处理价格统一字段,然后再画分布图复盘一下是否仍有双峰。如果数据本身真实存在两个价格带,这种「双峰」就是市场结构的反映,此时应该进一步分析两个峰的车型特征差异,而不是当成数据错误删掉。
6. 把可视化结果变成可复用的分析看板:一个纵向对比的小技巧
分析完 2024 年数据,大部分人会停在「画完保存图片」这一步。想更进一步,把整条分析链路沉淀成可复用代码,核心手法是拆函数。
def load_and_clean(path): df = pd.read_csv(path) # 把第 2 章的所有清洗逻辑放进来 return df def plot_price_hist(df, year, ax): ax.hist(df["price_wan"], bins=30, alpha=0.6, label=f"{year}") ax.set_xlabel("价格(万元)") ax.set_ylabel("车型数量") ax.legend()清洗函数只负责输出干净数据,绘图函数只负责画图。这样拿到 2025 年的数据,只要数据格式不变,替换文件路径就能跑出同一套分析。做纵向对比时,把两个年份的价格直方图画在同一张图上,配合半透明填充直观呈现在售车型价格分布迁移的方向。如果某个价格带车型数量明显增加,通常意味着市场竞争在下沉或该价格带出现技术突破。这个复用习惯让数据分析从一个「一次性交付物」变成可积累的分析资产。
我最初做这类分析时也追求图表炫酷,后来发现最值得投入时间的不是配色和动画,而是把清洗规则设计得足够健壮,让换一年数据进来不翻车。可视化只是把数据里的规律讲清楚,真正决定分析质量的是前面的功夫。希望这些细节能让你少走弯路,希望帮到你。
本文还有配套的精品资源,点击获取