
简介本资源是一个面向新能源汽车市场研究者、能源政策分析人员及数据科学学习者的综合型数据分析平台聚焦销量预测、能源价格关联性建模与充电基础设施空间布局评估三大核心问题。包内含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 数据源的选取逻辑与价值这个项目选取了四个核心数据维度它们共同构成了观察新能源汽车市场的“四象限”汽车之家销量与售价数据这是市场的“体温计”。销量数据反映了终端市场的真实接纳度是结果指标售价数据尤其是不同配置、不同地区的成交价则能透视品牌溢价、促销策略和消费者支付意愿。将两者结合可以计算市场规模、品牌份额并洞察“以价换量”等策略的有效性。国际原油价格数据这是外部环境的“晴雨表”。传统燃油车的使用成本与油价强相关。油价的剧烈波动会直接影响消费者对燃油车和新能源汽车全生命周期成本的比较。通常油价进入上升通道时会利好新能源汽车的短期关注度和销量。这部分数据为销量分析提供了一个关键的外部解释变量。中国充电桩分布数据这是基础设施的“地图”。新能源汽车的推广尤其是纯电动汽车严重依赖充电网络的完善程度。充电桩的分布密度、位置高速服务区、商业中心、居民区直接关系到用户的里程焦虑和购车决策。分析其空间分布不仅能评估当前基建水平还能预测未来的“补能荒漠”和“热点区域”。选择这三类数据意图是构建一个“市场表现销量售价-外部动因油价-基础支撑充电桩”的立体分析框架。单一维度的分析容易片面而这个框架能让我们看到更完整的图景。2.2 数据采集的技术实现与避坑指南数据采集是第一步也是最容易踩坑的一步。我的原则是在合规的前提下优先选择稳定的数据源和稳健的技术方案。对于汽车之家这类结构化网站的数据我主要使用Python 的requests库配合BeautifulSoup或lxml进行解析。这里的关键在于模拟正常的浏览器访问避免被反爬机制拦截。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 fhttps://xxx.xxx.com/sales_rank/{month}/{city}.html try: resp requests.get(url, headersheaders, timeout10) 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(symbolCL, perioddaily) print(oil_df.head())对于充电桩分布数据来源可能更分散。一些政府开放数据平台、充电桩运营商官网或聚合平台如特来电、星星充电的开发者中心可能提供API或可下载的数据集。如果只能获取到带坐标的POI列表那么数据清洗的重点将是坐标纠偏和格式标准化统一为WGS84经纬度。一个重要的心得在编写爬虫时一定要把异常处理和数据持久化做在第一步。每获取一页或一批数据就立即保存到本地文件如CSV或数据库并记录日志。千万不要让程序在内存中累积大量数据后一次性写入一旦中途出错或网络中断前功尽弃。我习惯使用csv.writer或pandas.DataFrame.to_csv的追加模式modea。3. 数据清洗、整合与探索性分析3.1 多源数据的清洗标准化流程原始数据通常是“脏”的直接用于分析会得出错误结论。清洗是保证分析质量的基石。缺失值处理销量/售价数据对于个别车型某个月份的缺失如果数量少可以考虑用前后月份的平均值插值或直接删除该条记录。如果大量缺失则需要反思数据源是否可靠。油价数据交易日数据一般连续遇到节假日缺失通常无需处理保持日期索引的连续性即可分析时按时间序列方法处理。充电桩数据关键字段如坐标、运营商缺失则这条记录价值不大可直接删除。异常值处理销量数据突然出现的极高或极低值如某车型销量为0或暴增10倍需要结合新闻事件新车上市、停产、重大促销进行核实判断是数据错误还是真实情况。可以使用箱线图或“均值±3倍标准差”的方法进行初步识别。售价数据明显低于市场指导价或高得离谱的价格可能是报价错误或包含特殊条件如库存车、展车需谨慎对待或剔除。坐标数据经纬度明显超出中国国境范围属于错误数据必须清洗。数据格式标准化将日期字段统一转换为datetime格式。将销量、售价、油价等数值字段转换为float或int。将车型、品牌、城市等文本字段进行统一命名例如“特斯拉 Model 3”和“Model 3”应统一。数据整合 这是项目的关键一步。我们需要一个时间维度和一个空间维度作为连接各表的桥梁。创建主分析表以“时间-空间”为骨架。例如创建一个以月份和省份/城市为索引的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, onmonth, howleft) # 3. 合并充电桩数据充电桩数据假设为最新状态与月份无关或按年更新 df_main pd.merge(df_main, df_pile, oncity, howleft) print(df_main.head())3.2 探索性数据分析用可视化发现故事在建模之前必须先用图表直观地感受数据。我主要使用matplotlib和seaborn。销量与油价的时间序列图将新能源汽车月度总销量曲线和国际原油价格曲线画在同一张图上采用双Y轴可以直观看到两者在关键时间点的走势关联。售价与销量的散点图/气泡图以平均售价为X轴销量为Y轴气泡大小可以代表市场份额。观察是否存在“高销量低价格”的性价比爆款或“高价格低销量”的豪华小众车型。充电桩分布的热力图利用folium或kepler.gl库将充电桩坐标在地图上打点可以立刻看出哪些城市群长三角、珠三角、京津冀密度高哪些省份存在空白。各省份销量与充电桩数量的对比条形图看基础设施与市场表现是否匹配。有些省份可能充电桩很多但销量一般基建超前有些则相反基建滞后。这些图表不仅能指导后续的建模方向比如销量和油价看起来有滞后相关性那建模时就可以考虑加入油价的滞后项还能直接产出有价值的洞察成为最终报告的重要组成部分。4. 核心分析模型一销量预测线性回归与灰色预测4.1 多元线性回归寻找关键驱动因子当我说“用线性回归分析销量”时指的绝不是简单的一元回归而是多元线性回归。目标是建立一个方程量化几个关键因素对销量的影响程度。模型构建思路 假设我们想预测某个品牌或整体市场下个月的新能源汽车销量sales。根据之前的分析我们可能选取以下自变量lag_oil_price上个月的国际油价滞后一期因为油价影响有延迟。avg_price本月的市场平均售价反映价格竞争力。pile_density本城市的充电桩密度每平方公里充电桩数量反映基建水平。policy_dummy政策虚拟变量例如某月是否有新的购车补贴政策出台有则为1无则为0。seasonality季节性因素可以用月份的数字1-12或使用哑变量。使用statsmodels或scikit-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()的输出会非常详细。我们要重点关注以下几点R-squared模型解释了销量波动的多大比例。对于社会经济数据0.6以上就算不错。系数coef及其P值P|t|每个自变量的系数大小代表了影响力度正负代表方向。P值小于0.05通常认为该变量影响显著。例如lag_oil_price系数为正且显著就证实了“油价上涨推高新能源销量”的假设。共线性检查如果avg_price和pile_density的系数符号反常比如价格越高销量预测反而越高或者方差膨胀因子VIF很高10可能存在多重共线性问题。这时需要考虑剔除相关性高的变量或使用主成分回归等方法。实操心得线性回归模型的可解释性是其最大优点。你可以直接告诉业务方“在其他条件不变的情况下油价每上涨10美元我们预测下个月销量会增加大约X辆。”这种结论非常有力。但前提是你的数据质量和变量选择要经得起推敲。4.2 灰色预测GM(1,1)应对小样本数据的趋势外推线性回归需要多个自变量但有时我们只有一条销量时间序列且数据量不大比如只有两三年的月度数据。这时灰色预测模型GM(1,1)就派上用场了。它特别适合用于短期趋势预测核心思想是通过对原始数据序列进行累加生成弱化随机性挖掘潜在规律。GM(1,1)建模步骤简述设有原始销量序列X0 [x0(1), x0(2), ..., x0(n)]。进行一次累加生成新序列X1其中x1(k) sum(x0(1) to x0(k))。建立X1的微分方程即GM(1,1)模型的白化方程求解其时间响应式。将响应式还原得到原始序列的预测值。Python中可以用greytheory库或自己实现。# 示例使用简单的实现进行灰色预测 import numpy as np def gm11(x0, predict_step1): 简单的GM(1,1)预测函数 x0: 原始序列一维数组 predict_step: 预测步长 x0 np.array(x0, dtypenp.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_step1) print(f原始数据拟合值: {fitted}) print(f未来1期预测值: {predicted})灰色预测的适用场景与局限优点所需数据少短期预测精度有时较高适用于趋势性明显、指数增长特征的数据。缺点对波动大的数据预测效果差长期预测误差会放大。它本质上是一种指数平滑外推缺乏因果解释。我的用法我通常将GM(1,1)作为线性回归模型的补充。当需要快速做一个简单的、基于纯历史趋势的销量展望时用它。对于重要的决策我会以线性回归的因果分析为主用灰色预测的结果作为趋势参考再结合专家判断。5. 核心分析模型二充电桩空间聚类分析充电桩的分布不是随机的它呈现出明显的聚集性。通过空间聚类分析我们可以识别出充电桩布局的“热点区域”和“盲区”为运营决策提供支持。5.1 聚类算法选择与数据预处理最常用的空间聚类算法是DBSCAN。与K-Means需要预先指定簇数不同DBSCAN能基于密度自动发现任意形状的簇并识别噪声点孤立的充电桩这非常符合空间数据的特性。在聚类之前数据预处理至关重要坐标转换确保所有充电桩的经纬度坐标在同一坐标系下如WGS84。计算距离矩阵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(eps3, min_samples5, metricprecomputed).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然后根据业务理解调整。结果解读核心簇识别出的每个簇代表一个充电桩密集区。可以计算每个簇的中心点经纬度均值、包含的充电桩数量、快慢充比例等。噪声点这些孤立的充电桩可能位于偏远地区、早期试点位置或是数据错误。需要结合地图查看具体位置。业务应用热点验证看簇中心是否与大型商圈、交通枢纽、住宅区重合验证布局的合理性。盲区发现在城市地图上标出所有簇的覆盖范围空白区域可能就是潜在的需求缺口。可以进一步叠加人口热力图、车流量数据优先在“高需求、低供给”的盲区规划新桩。运营策略对于大型簇如高速公路服务区集群可以分析其服务能力是否饱和对于小型簇可以评估其运营效率。一个常见的坑直接对全国范围的充电桩做聚类会因为尺度太大而效果不佳。更好的做法是分城市或分区域进行。例如先按省份或城市筛选数据再分别进行聚类分析这样参数设置更有针对性结果也更精细。6. 分析结果整合与可视化呈现数据分析的最终价值在于洞察和沟通。将上述所有分析结果整合成一个连贯的故事并通过专业的可视化呈现出来是项目的收官之作。6.1 构建综合仪表板我不会只给出一堆散落的图表和数字。我会使用Plotly Dash 或 Streamlit快速搭建一个交互式仪表板。这个仪表板可能包含以下几个视图市场总览页一个时间序列折线图展示历史销量、油价、预测销量的对比。一个地图用深浅色表示各省份新能源汽车渗透率销量/汽车总销量。一个条形图展示Top 10品牌的市场份额变化。因素分析页展示线性回归模型的关键结果一个表格显示各变量的系数、P值和影响显著性。一个散点图矩阵展示销量与油价、售价、充电桩密度等关键变量的两两关系。基础设施分析页一个高亮显示充电桩聚类结果的地图。不同簇用不同颜色标记噪声点用灰色显示。点击某个簇可以弹出该簇的详细信息桩数量、类型、平均利用率如果有数据等。一个对比图表展示充电桩密度TOP10城市与销量TOP10城市的重合度。6.2 从数据到决策建议基于整合分析可以提炼出有操作性的结论趋势判断“根据模型在未来三个月若油价维持在每桶XX美元以上且无重大政策变动新能源汽车月度销量有望达到YY万辆。灰色预测模型也支持这一增长趋势。”敏感性分析“我们的模型显示售价每降低1万元对销量的拉动效应约为Z%。这为制定促销策略提供了量化依据。”风险提示“当前充电桩布局在三四线城市及部分城乡结合部存在明显盲区这可能是制约这些市场爆发的主要瓶颈。建议优先在这些区域的交通干道和商业中心布局。”机会发现“聚类分析发现A城市和B城市之间高速公路沿线的充电桩形成了连贯的集群已初步形成‘充电走廊’可考虑在此走廊加大品牌营销投入。”最后一点心得数据分析项目最难的不是代码和模型而是业务理解和故事讲述。你必须清楚每一个数据背后的业务含义知道你的分析结果能帮助谁解决什么问题。在报告或演示中切忌罗列技术细节。要从听众可能是管理层、市场部、投资经理的角度出发用他们关心的语言市场份额、增长机会、风险成本来呈现你的发现。这个项目从数据采集到最终建议的完整链条正是锻炼这种“技术-业务”翻译能力的绝佳实践。本文还有配套的精品资源点击获取