新能源汽车市场数据分析实战:从爬虫到预测与空间聚类的完整工具箱
2026/9/2 9:53:57 网站建设 项目流程

简介:本资源是一个面向新能源汽车市场研究者、能源政策分析人员及数据科学学习者的综合型数据分析平台,聚焦销量预测、能源价格关联性建模与充电基础设施空间布局评估三大核心问题。包内含153个文件,涵盖45个JavaScript爬虫脚本(用于汽车之家等平台动态数据采集)、33个Excel与18个CSV格式的结构化数据集(包括2014–2022年新能源汽车月度销量、WTI/Brent原油日/周价格、全国充电桩地理坐标及运营商信息),以及9个Python分析脚本、1个Jupyter Notebook(含线性回归与灰色预测GM(1,1)模型实现)和空间聚类可视化代码。压缩包大小为60.04MB,目录组织清晰,支持端到端复现从数据获取、清洗、建模到地理热力图生成的完整分析链路。已有42人下载学习,适合具备基础Python与统计建模能力的研究者开展实证分析或政策模拟。

1. 项目概述:一个数据驱动的市场研究工具箱

最近在整理一个挺有意思的项目,我把它叫做“新能源汽车市场数据研究工具箱”。这个项目的核心,说白了,就是通过爬虫、数据清洗、分析和可视化这一整套流程,把几个看似独立的数据源——汽车销量、车型售价、国际油价、充电桩分布——给串起来,形成一个能洞察市场趋势的闭环。这活儿听起来像是咨询公司或者券商研究员干的,但其实对于车企的产品规划、投资机构的赛道分析,甚至是充电桩运营商的选址决策,都有实实在在的参考价值。

我之所以动手做这个,是因为发现市面上很多分析报告要么数据源单一,要么结论过于笼统。比如,分析销量只谈环比同比,很少结合油价波动对消费者购车意愿的即时影响;讨论充电桩布局,也多是宏观统计,缺乏从空间密度和车型销量匹配度的微观视角。这个项目就是想填补这些空白,用数据说话,而不是凭感觉猜测。整个流程从原始数据的获取开始,经过清洗、整合、建模,到最后输出直观的图表和可解释的结论,算是一个完整的数据分析实战案例。无论你是想入门数据分析的学生,还是需要快速验证市场假设的从业者,这套方法和代码都能提供一个清晰的框架。

2. 核心数据源解析与采集策略

2.1 数据源的选取逻辑与价值

这个项目选取了四个核心数据维度,它们共同构成了观察新能源汽车市场的“四象限”:

  1. 汽车之家销量与售价数据:这是市场的“体温计”。销量数据反映了终端市场的真实接纳度,是结果指标;售价数据(尤其是不同配置、不同地区的成交价)则能透视品牌溢价、促销策略和消费者支付意愿。将两者结合,可以计算市场规模、品牌份额,并洞察“以价换量”等策略的有效性。
  2. 国际原油价格数据:这是外部环境的“晴雨表”。传统燃油车的使用成本与油价强相关。油价的剧烈波动会直接影响消费者对燃油车和新能源汽车全生命周期成本的比较。通常,油价进入上升通道时,会利好新能源汽车的短期关注度和销量。这部分数据为销量分析提供了一个关键的外部解释变量。
  3. 中国充电桩分布数据:这是基础设施的“地图”。新能源汽车的推广,尤其是纯电动汽车,严重依赖充电网络的完善程度。充电桩的分布密度、位置(高速服务区、商业中心、居民区)直接关系到用户的里程焦虑和购车决策。分析其空间分布,不仅能评估当前基建水平,还能预测未来的“补能荒漠”和“热点区域”。

选择这三类数据,意图是构建一个“市场表现(销量售价)-外部动因(油价)-基础支撑(充电桩)”的立体分析框架。单一维度的分析容易片面,而这个框架能让我们看到更完整的图景。

2.2 数据采集的技术实现与避坑指南

数据采集是第一步,也是最容易踩坑的一步。我的原则是:在合规的前提下,优先选择稳定的数据源和稳健的技术方案。

对于汽车之家这类结构化网站的数据,我主要使用Python 的requests库配合BeautifulSouplxml进行解析。这里的关键在于模拟正常的浏览器访问,避免被反爬机制拦截。

import requests from bs4 import BeautifulSoup import pandas as pd import time headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } def fetch_car_sales_data(month, city): """获取指定月份和城市的汽车销量数据(示例)""" # 构造目标URL,这里需要根据网站实际结构分析 url = f"https://xxx.xxx.com/sales_rank/{month}/{city}.html" try: resp = requests.get(url, headers=headers, timeout=10) resp.raise_for_status() # 检查请求是否成功 resp.encoding = 'utf-8' soup = BeautifulSoup(resp.text, 'lxml') # 解析表格数据,这里需要根据实际HTML结构编写选择器 # 例如:soup.select('table.sales-rank tr') # 将解析出的数据存入列表或字典 data_list = [] # ... 具体的解析逻辑 ... return pd.DataFrame(data_list) except requests.RequestException as e: print(f"请求失败: {url}, 错误: {e}") return pd.DataFrame() # 使用示例 # df_beijing = fetch_car_sales_data('2024-03', 'beijing')

注意:实际操作中,很多网站的数据是通过异步接口(XHR)加载的。这时需要用浏览器的开发者工具(F12)的“网络(Network)”选项卡,查找真正的数据接口(通常是返回JSON格式的请求)。直接请求这个接口,比解析渲染后的HTML更高效、更稳定。此外,务必在请求中添加合理的延时(如time.sleep(2)),避免对目标服务器造成过大压力,这也是基本的网络礼仪。

对于国际原油价格数据,我推荐直接使用金融数据API,比如yfinance库(雅虎财经)或者akshare库(国内开源金融数据接口)。它们稳定、免费,且数据格式规整。

import akshare as ak # 获取WTI原油期货历史数据 oil_df = ak.futures_foreign_hist(symbol="CL", period="daily") print(oil_df.head())

对于充电桩分布数据,来源可能更分散。一些政府开放数据平台、充电桩运营商官网或聚合平台(如特来电、星星充电的开发者中心)可能提供API或可下载的数据集。如果只能获取到带坐标的POI列表,那么数据清洗的重点将是坐标纠偏和格式标准化(统一为WGS84经纬度)。

一个重要的心得:在编写爬虫时,一定要把异常处理数据持久化做在第一步。每获取一页或一批数据,就立即保存到本地文件(如CSV)或数据库,并记录日志。千万不要让程序在内存中累积大量数据后一次性写入,一旦中途出错或网络中断,前功尽弃。我习惯使用csv.writerpandas.DataFrame.to_csv的追加模式(mode='a')。

3. 数据清洗、整合与探索性分析

3.1 多源数据的清洗标准化流程

原始数据通常是“脏”的,直接用于分析会得出错误结论。清洗是保证分析质量的基石。

  1. 缺失值处理
    • 销量/售价数据:对于个别车型某个月份的缺失,如果数量少,可以考虑用前后月份的平均值插值,或直接删除该条记录。如果大量缺失,则需要反思数据源是否可靠。
    • 油价数据:交易日数据一般连续,遇到节假日缺失,通常无需处理,保持日期索引的连续性即可,分析时按时间序列方法处理。
    • 充电桩数据:关键字段如坐标、运营商缺失,则这条记录价值不大,可直接删除。
  2. 异常值处理
    • 销量数据:突然出现的极高或极低值(如某车型销量为0或暴增10倍),需要结合新闻事件(新车上市、停产、重大促销)进行核实,判断是数据错误还是真实情况。可以使用箱线图或“均值±3倍标准差”的方法进行初步识别。
    • 售价数据:明显低于市场指导价或高得离谱的价格,可能是报价错误或包含特殊条件(如库存车、展车),需谨慎对待或剔除。
    • 坐标数据:经纬度明显超出中国国境范围,属于错误数据,必须清洗。
  3. 数据格式标准化
    • 将日期字段统一转换为datetime格式。
    • 将销量、售价、油价等数值字段转换为floatint
    • 将车型、品牌、城市等文本字段进行统一命名(例如,“特斯拉 Model 3”和“Model 3”应统一)。
  4. 数据整合: 这是项目的关键一步。我们需要一个时间维度和一个空间维度作为连接各表的桥梁。
    • 创建主分析表:以“时间-空间”为骨架。例如,创建一个以月份省份/城市为索引的DataFrame。
    • 关联销量售价数据:按月份和车型所属品牌的主流销售区域进行聚合(如某品牌在某省月的总销量、平均售价),合并到主表。
    • 关联油价数据:将国际油价的月度平均值(或月初值)作为一个新的列,添加到每一个时间索引上。这里假设油价对全国的影响是同质的。
    • 关联充电桩数据:按省份/城市统计充电桩总量、快慢充比例、运营商数量等指标,作为静态或低频更新的特征并入主表。
import pandas as pd # 假设已有清洗好的数据框 df_sales = pd.read_csv('cleaned_sales.csv') # 包含 month, city, brand, sales_volume, avg_price df_oil = pd.read_csv('cleaned_oil.csv') # 包含 month, oil_price df_pile = pd.read_csv('cleaned_pile.csv') # 包含 city, pile_count, fast_pile_ratio # 1. 聚合销量数据:计算每个城市每个月的总销量和平均售价(按销量加权) df_sales_agg = df_sales.groupby(['month', 'city']).agg( total_sales=('sales_volume', 'sum'), weighted_avg_price=('avg_price', lambda x: (x * df_sales.loc[x.index, 'sales_volume']).sum() / df_sales.loc[x.index, 'sales_volume'].sum()) ).reset_index() # 2. 合并油价数据(油价与城市无关,直接按月份合并) df_main = pd.merge(df_sales_agg, df_oil, on='month', how='left') # 3. 合并充电桩数据(充电桩数据假设为最新状态,与月份无关,或按年更新) df_main = pd.merge(df_main, df_pile, on='city', how='left') print(df_main.head())

3.2 探索性数据分析:用可视化发现故事

在建模之前,必须先用图表直观地感受数据。我主要使用matplotlibseaborn

  • 销量与油价的时间序列图:将新能源汽车月度总销量曲线和国际原油价格曲线画在同一张图上(采用双Y轴),可以直观看到两者在关键时间点的走势关联。
  • 售价与销量的散点图/气泡图:以平均售价为X轴,销量为Y轴,气泡大小可以代表市场份额。观察是否存在“高销量低价格”的性价比爆款,或“高价格低销量”的豪华小众车型。
  • 充电桩分布的热力图:利用foliumkepler.gl库,将充电桩坐标在地图上打点,可以立刻看出哪些城市群(长三角、珠三角、京津冀)密度高,哪些省份存在空白。
  • 各省份销量与充电桩数量的对比条形图:看基础设施与市场表现是否匹配。有些省份可能充电桩很多但销量一般(基建超前),有些则相反(基建滞后)。

这些图表不仅能指导后续的建模方向(比如,销量和油价看起来有滞后相关性,那建模时就可以考虑加入油价的滞后项),还能直接产出有价值的洞察,成为最终报告的重要组成部分。

4. 核心分析模型一:销量预测(线性回归与灰色预测)

4.1 多元线性回归:寻找关键驱动因子

当我说“用线性回归分析销量”时,指的绝不是简单的一元回归,而是多元线性回归。目标是建立一个方程,量化几个关键因素对销量的影响程度。

模型构建思路: 假设我们想预测某个品牌或整体市场下个月的新能源汽车销量(sales)。根据之前的分析,我们可能选取以下自变量:

  • lag_oil_price:上个月的国际油价(滞后一期,因为油价影响有延迟)。
  • avg_price:本月的市场平均售价(反映价格竞争力)。
  • pile_density:本城市的充电桩密度(每平方公里充电桩数量,反映基建水平)。
  • policy_dummy:政策虚拟变量(例如,某月是否有新的购车补贴政策出台,有则为1,无则为0)。
  • seasonality:季节性因素(可以用月份的数字1-12,或使用哑变量)。

使用statsmodelsscikit-learn可以方便地建立模型。

import statsmodels.api as sm import pandas as pd # 假设 df_main 是整合好的数据,并已创建了滞后变量等特征 df_model = df_main.copy() # 添加滞后一期的油价 df_model['lag_oil_price'] = df_model.groupby('city')['oil_price'].shift(1) # 删除含有缺失值的行(因为创建了滞后变量) df_model = df_model.dropna() # 定义自变量和因变量 X = df_model[['lag_oil_price', 'weighted_avg_price', 'pile_density', 'policy_dummy', 'month']] y = df_model['total_sales'] # 为X添加常数项(截距) X = sm.add_constant(X) # 建立OLS模型 model = sm.OLS(y, X).fit() # 打印详细的回归结果 print(model.summary())

结果解读与注意事项model.summary()的输出会非常详细。我们要重点关注以下几点:

  1. R-squared:模型解释了销量波动的多大比例。对于社会经济数据,0.6以上就算不错。
  2. 系数(coef)及其P值(P>|t|):每个自变量的系数大小代表了影响力度,正负代表方向。P值小于0.05通常认为该变量影响显著。例如,lag_oil_price系数为正且显著,就证实了“油价上涨推高新能源销量”的假设。
  3. 共线性检查:如果avg_pricepile_density的系数符号反常(比如价格越高销量预测反而越高),或者方差膨胀因子(VIF)很高(>10),可能存在多重共线性问题。这时需要考虑剔除相关性高的变量,或使用主成分回归等方法。

实操心得:线性回归模型的可解释性是其最大优点。你可以直接告诉业务方:“在其他条件不变的情况下,油价每上涨10美元,我们预测下个月销量会增加大约X辆。”这种结论非常有力。但前提是,你的数据质量和变量选择要经得起推敲。

4.2 灰色预测GM(1,1):应对小样本数据的趋势外推

线性回归需要多个自变量,但有时我们只有一条销量时间序列,且数据量不大(比如只有两三年的月度数据)。这时,灰色预测模型GM(1,1)就派上用场了。它特别适合用于短期趋势预测,核心思想是通过对原始数据序列进行累加生成,弱化随机性,挖掘潜在规律。

GM(1,1)建模步骤简述

  1. 设有原始销量序列X0 = [x0(1), x0(2), ..., x0(n)]
  2. 进行一次累加生成新序列X1,其中x1(k) = sum(x0(1) to x0(k))
  3. 建立X1的微分方程(即GM(1,1)模型的白化方程),求解其时间响应式。
  4. 将响应式还原,得到原始序列的预测值。

Python中可以用greytheory库或自己实现。

# 示例:使用简单的实现进行灰色预测 import numpy as np def gm11(x0, predict_step=1): """ 简单的GM(1,1)预测函数 x0: 原始序列,一维数组 predict_step: 预测步长 """ x0 = np.array(x0, dtype=np.float64) x1 = x0.cumsum() # 1-AGO z1 = (x1[:-1] + x1[1:]) / 2.0 # 紧邻均值生成序列 B = np.vstack([-z1, np.ones_like(z1)]).T Y = x0[1:].reshape(-1, 1) # 最小二乘法求解参数 a, b [[a], [b]] = np.linalg.inv(B.T @ B) @ B.T @ Y # 时间响应式 def f(k): return (x0[0] - b/a) * np.exp(-a * (k-1)) + b/a # 预测 pred_x1 = [f(i) for i in range(1, len(x0) + predict_step + 1)] pred_x0 = [pred_x1[0]] + [pred_x1[i] - pred_x1[i-1] for i in range(1, len(pred_x1))] return pred_x0[:len(x0)], pred_x0[len(x0):] # 返回拟合值和预测值 # 使用示例:用前12个月数据预测第13个月 historical_sales = [20000, 22000, 25000, 23000, 28000, 30000, 32000, 35000, 38000, 40000, 42000, 45000] fitted, predicted = gm11(historical_sales, predict_step=1) print(f"原始数据拟合值: {fitted}") print(f"未来1期预测值: {predicted}")

灰色预测的适用场景与局限

  • 优点:所需数据少,短期预测精度有时较高,适用于趋势性明显、指数增长特征的数据。
  • 缺点:对波动大的数据预测效果差,长期预测误差会放大。它本质上是一种指数平滑外推,缺乏因果解释。
  • 我的用法:我通常将GM(1,1)作为线性回归模型的补充。当需要快速做一个简单的、基于纯历史趋势的销量展望时用它。对于重要的决策,我会以线性回归的因果分析为主,用灰色预测的结果作为趋势参考,再结合专家判断。

5. 核心分析模型二:充电桩空间聚类分析

充电桩的分布不是随机的,它呈现出明显的聚集性。通过空间聚类分析,我们可以识别出充电桩布局的“热点区域”和“盲区”,为运营决策提供支持。

5.1 聚类算法选择与数据预处理

最常用的空间聚类算法是DBSCAN。与K-Means需要预先指定簇数不同,DBSCAN能基于密度自动发现任意形状的簇,并识别噪声点(孤立的充电桩),这非常符合空间数据的特性。

在聚类之前,数据预处理至关重要:

  1. 坐标转换:确保所有充电桩的经纬度坐标在同一坐标系下(如WGS84)。
  2. 计算距离矩阵:DBSCAN需要基于点之间的距离进行聚类。对于地理坐标,必须使用球面距离(如Haversine公式),而不是欧氏距离,因为地球是圆的。
from sklearn.cluster import DBSCAN from sklearn.metrics.pairwise import haversine_distances from math import radians import numpy as np # 假设 piles 是一个包含经纬度的数组, shape: (n_samples, 2), 格式 [经度, 纬度] # 例如:piles = np.array([[116.4, 39.9], [121.5, 31.2], ...]) # 将角度转换为弧度 piles_rad = np.radians(piles) # 计算Haversine距离矩阵 (单位:公里) # 地球平均半径约6371公里 distance_matrix = haversine_distances(piles_rad) * 6371 # 使用DBSCAN进行聚类 # eps: 邻域半径(公里),例如3公里内的点认为是邻居 # min_samples: 形成一个簇所需的最小点数,例如5个 clustering = DBSCAN(eps=3, min_samples=5, metric='precomputed').fit(distance_matrix) labels = clustering.labels_ # labels = -1 表示噪声点 # labels >= 0 表示簇的编号 n_clusters = len(set(labels)) - (1 if -1 in labels else 0) print(f"识别出 {n_clusters} 个聚类簇,有 {sum(labels==-1)} 个噪声点。")

5.2 参数调优与结果解读

DBSCAN的效果高度依赖两个参数:eps(邻域半径)和min_samples(最小点数)。

  • 如何确定eps:一个经验方法是绘制k-距离图。计算每个点到其第k个最近邻的距离,并排序绘图。距离的拐点(急剧上升处)可以作为eps的参考值。min_samples通常可以先设为2倍的数据维度(这里是2),然后根据业务理解调整。
  • 结果解读
    • 核心簇:识别出的每个簇,代表一个充电桩密集区。可以计算每个簇的中心点(经纬度均值)、包含的充电桩数量、快慢充比例等。
    • 噪声点:这些孤立的充电桩可能位于偏远地区、早期试点位置,或是数据错误。需要结合地图查看具体位置。
    • 业务应用
      1. 热点验证:看簇中心是否与大型商圈、交通枢纽、住宅区重合,验证布局的合理性。
      2. 盲区发现:在城市地图上标出所有簇的覆盖范围,空白区域可能就是潜在的需求缺口。可以进一步叠加人口热力图、车流量数据,优先在“高需求、低供给”的盲区规划新桩。
      3. 运营策略:对于大型簇(如高速公路服务区集群),可以分析其服务能力是否饱和;对于小型簇,可以评估其运营效率。

一个常见的坑:直接对全国范围的充电桩做聚类,会因为尺度太大而效果不佳。更好的做法是分城市或分区域进行。例如,先按省份或城市筛选数据,再分别进行聚类分析,这样参数设置更有针对性,结果也更精细。

6. 分析结果整合与可视化呈现

数据分析的最终价值在于洞察和沟通。将上述所有分析结果整合成一个连贯的故事,并通过专业的可视化呈现出来,是项目的收官之作。

6.1 构建综合仪表板

我不会只给出一堆散落的图表和数字。我会使用Plotly Dash 或 Streamlit快速搭建一个交互式仪表板。这个仪表板可能包含以下几个视图:

  1. 市场总览页
    • 一个时间序列折线图,展示历史销量、油价、预测销量的对比。
    • 一个地图,用深浅色表示各省份新能源汽车渗透率(销量/汽车总销量)。
    • 一个条形图,展示Top 10品牌的市场份额变化。
  2. 因素分析页
    • 展示线性回归模型的关键结果:一个表格显示各变量的系数、P值和影响显著性。
    • 一个散点图矩阵,展示销量与油价、售价、充电桩密度等关键变量的两两关系。
  3. 基础设施分析页
    • 一个高亮显示充电桩聚类结果的地图。不同簇用不同颜色标记,噪声点用灰色显示。
    • 点击某个簇,可以弹出该簇的详细信息:桩数量、类型、平均利用率(如果有数据)等。
    • 一个对比图表,展示充电桩密度TOP10城市与销量TOP10城市的重合度。

6.2 从数据到决策建议

基于整合分析,可以提炼出有操作性的结论:

  • 趋势判断:“根据模型,在未来三个月,若油价维持在每桶XX美元以上,且无重大政策变动,新能源汽车月度销量有望达到YY万辆。灰色预测模型也支持这一增长趋势。”
  • 敏感性分析:“我们的模型显示,售价每降低1万元,对销量的拉动效应约为Z%。这为制定促销策略提供了量化依据。”
  • 风险提示:“当前充电桩布局在三四线城市及部分城乡结合部存在明显盲区,这可能是制约这些市场爆发的主要瓶颈。建议优先在这些区域的交通干道和商业中心布局。”
  • 机会发现:“聚类分析发现,A城市和B城市之间高速公路沿线的充电桩形成了连贯的集群,已初步形成‘充电走廊’,可考虑在此走廊加大品牌营销投入。”

最后一点心得:数据分析项目最难的不是代码和模型,而是业务理解故事讲述。你必须清楚每一个数据背后的业务含义,知道你的分析结果能帮助谁解决什么问题。在报告或演示中,切忌罗列技术细节。要从听众(可能是管理层、市场部、投资经理)的角度出发,用他们关心的语言(市场份额、增长机会、风险成本)来呈现你的发现。这个项目从数据采集到最终建议的完整链条,正是锻炼这种“技术-业务”翻译能力的绝佳实践。

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

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

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

立即咨询