简介:针对新能源充电站负荷预测研究提供了一套结构化数据集,涵盖时序用电记录、充电行为特征、气象与假期等环境因素以及站点属性,适用于高校师生、算法工程师及电力运营人员搭建负荷预测模型。包体共32个文件,以Python脚本、CSV时序数据、配置文件及说明文档为主,并附有备份文件,整体约1.97MB,便于快速解压使用。数据来自珀斯、帕洛阿尔托、博尔德等不同地区的充电站,具有多场景可比性;配套的Python代码包含数据加载、模型构建、指标评价等模块,可支撑从数据处理到预测实验的完整流程。借助该数据集可开展多维因素对充电负荷影响的实证分析,验证动态定价或需求响应策略,辅助充电网络规划与电网安全运行。目前已有82人学习下载,适合作为相关课题起步的训练数据与基线工具。
1. 新能源充电站负荷预测数据集:为什么说它比模型更值得先投入
做充电站负荷预测的人,十有八九第一版模型都翻车在数据上,而不是算法上。我见过不少团队拿着公开的电力负荷数据硬套充电场景,结果模型在深夜低谷期表现尚可,一到工作日早高峰和节假日长途出行就完全失真——原因很简单:充电站的负荷不是单纯的用电曲线,它是「车来了才用电」的随机过程,受通勤习惯、剩余电量、天气、商圈活动、电价时段等多重因素叠加。如果你手上没有一份把时间序列、充电行为和环境特征对齐好的数据集,再好的Transformer和LSTM都是在黑匣子里瞎猜。
这篇笔记就围绕「新能源充电站负荷预测数据集」这个方向,把三件事讲透:这类数据集到底该长什么样、怎么从原始充电订单和气象数据自己构建一份能用的小样本数据集、以及那些会让预测结果集体漂移的坑。适合正在做充电桩运营调度、有序充电策略或站端容量规划的从业者,也能给研究时间序列预测的同学一份能直接上手的落地方案。数据是这行的地基,先把地基铺对了,模型才有资格谈精度。
2. 负荷预测数据集的三层结构:时间序列、充电行为与环境因素如何对齐
2.1 为什么单一负荷曲线不够用:充电负荷的「三重随机性」
传统电力负荷预测面对的是相对稳定的用户用电行为,而充电站负荷天然带着三重随机性:第一重是时间随机性,用户什么时刻到站、停留多久,服从通勤和出行计划,而不是固定作息;第二重是状态随机性,车辆进站时的SOC(剩余电量)不同,导致同一位用户在同一天的不同时刻充电功率差异巨大;第三重是环境随机性,气温直接决定电池加热和制冷耗电,雨雪天气又会影响出行意愿和充电时长。
如果数据集里只有聚合后的站端总负荷曲线,模型能学到的只有「过去这个时间点大概用多少电」,它无法回答「为什么今天上午10点的负荷比上周同期高了30%」。要回答这个问题,就必须把数据拆成三层:时间序列层、充电行为层、环境因素层,并且让三者在时间轴上严格对齐。我在实际构建数据集时,通常以15分钟为最小粒度做重采样,因为充电桩的功率上报周期一般是15分钟或30分钟,过细会导致大量空值,过粗又会抹掉充电开始的尖峰特征。
2.2 充电行为特征:从订单流水里挖出的9个关键字段
充电行为数据通常来自运营平台的订单流水,每个订单至少包含开始时间、结束时间、充电电量、充电时长、峰值功率、车辆SOC起点、SOC终点。把这些原始字段转成模型可用的特征时,我一般会保留或衍生出以下9个字段:
| 字段名 | 类型 | 说明 |
|---|---|---|
| start_time | datetime | 充电开始时间,用于提取小时、星期、节假日特征 |
| end_time | datetime | 充电结束时间,计算停留时长 |
| charging_duration | float | 实际充电时长,分钟 |
| stop_duration | float | 停留时长减充电时长,反映占位行为 |
| energy | float | 充电电量,kWh |
| max_power | float | 本次充电峰值功率,kW |
| soc_start | float | 进站SOC,0~1 |
| soc_end | float | 离站SOC,0~1 |
| average_power | float | 平均充电功率,kW |
这9个字段里,soc_start是最容易被忽略却又最关键的一个。同样在下午2点充电,一位SOC只剩10%的网约车司机和一位SOC还有60%的通勤车主,对站端负荷的影响完全不同:前者可能需要大功率快充一小时,后者可能只是小功率补电。如果你只把订单聚合到小时级负荷,就等于把这两种行为混成了一个平均数,模型的误差上限也就定死了。因此我建议在做小时级或15分钟级聚合时,额外保留该时段内所有订单的soc_start平均值和中位数,这一列特征对提升预测精度非常明显。
2.3 环境因素特征:温度不是单一数值,要拆成「体感负荷」
环境数据很容易被粗暴处理成「当天气温一个数、是否下雨一个布尔值」,这是大多数数据集的一个通病。实际上,温度对充电负荷的影响是非线性的:在0℃以下,电池加热系统会额外消耗大量电量;在35℃以上,电池散热和座舱预冷也会推高能耗。更关键的是,影响负荷的是「体感温度」和「温度变化率」,而不是单一气温值。
我构建环境特征时会同时加入当天最高温、最低温、平均温、温差、相对湿度、降水量、风速以及「是否极端天气」标记。其中温差这个特征特别有用:一天内温差超过10℃时,用户出行计划和充电需求的变化幅度显著增大,单纯把温度作为连续值输入模型,模型很难学到这种跳变。另外要注意,气象数据是日级的,而充电负荷是15分钟级的,做对齐时必须把日级数据向前填充(ffill),并且要避免用到未来信息——比如用当天平均温度预测当天的午间负荷,这在实操中是典型的泄露,但在很多公开数据集里却常见。
环境因素的滞后效应也不可忽视。高温天气的影响通常会持续到傍晚:白天暴晒后,傍晚电池温度依然偏高,散热需求持续存在。所以我会额外生成一个「三日滑动平均温度」特征,把环境影响的惯性喂给模型。这个特征在夏季月份的预测里贡献非常显著,甚至超过了原始气温本身。
3. 从零构建一份可用的负荷预测数据集:清洗、对齐与聚合实操
3.1 数据清洗:先处理订单流水里的三类脏数据
原始订单流水从来不会干净,主要有三类脏数据:第一类是充电时长极短的订单,比如扫码后几分钟内就结束,往往是设备故障或用户误操作;第二类是功率为零但时长很长的订单,可能是桩故障但订单未及时关闭;第三类是SOC数据缺失或越界,例如进站SOC填了负数。我在清洗时采用一套可复现的过滤规则:
import pandas as pd import numpy as np # 原始订单流水核心字段 df = pd.read_csv('charging_orders.csv', parse_dates=['start_time', 'end_time']) # 规则1:充电时长在5分钟到12小时之间,过滤误操作和占位异常 df = df[(df['charging_duration'] >= 5) & (df['charging_duration'] <= 720)] # 规则2:充电电量大于0且小于车辆电池容量上限(可配置,取200kWh) df = df[(df['energy'] > 0) & (df['energy'] < 200)] # 规则3:SOC起点在0到0.95之间,SOC终点大于起点 df = df[(df['soc_start'] >= 0) & (df['soc_start'] <= 0.95)] df = df[(df['soc_end'] > df['soc_start']) & (df['soc_end'] <= 1.0)] # 规则4:平均功率大于0,剔除异常上报 df = df[df['average_power'] > 0]这段清洗的逻辑重点在规则3:进站SOC超过0.95还充电的订单基本可以判定为数据异常,因为绝大多数用户不会在电量接近满的时候还接入快充;而SOC终点大于起点是物理约束,如果数据集里出现终点低于起点的记录,那基本是上报数据错位。平均功率过滤则能把设备上报周期错乱导致的整段零功率订单剔除掉。
清洗后的订单数量通常会比原始数据少10%到25%,这个幅度是正常的。如果过滤比例超过30%,说明源头数据质量有问题,建议先回到运营平台排查采集端,而不是靠清洗规则硬扛。
3.2 时间对齐与聚合:15分钟粒度下的负荷序列生成
清洗完成后,下一步是把每笔订单映射到时间轴上,再聚合成站端负荷序列。常见做法是:先把每笔订单展开成其在各15分钟区间内的充电电量(假设订单区间内功率恒定),再按站和区间汇总。展开时要注意订单跨越多个区间的情况,不能在订单结束时间那一格才记电量。
# 为每笔订单生成15分钟粒度的电量分布 def expand_order(row, freq_min=15): # 平均功率近似为订单周期内的恒定功率 power_kw = row['energy'] / (row['charging_duration'] / 60) # 生成时间区间边界(左闭右开) t_start = row['start_time'].floor(f'{freq_min}min') t_end = row['end_time'].ceil(f'{freq_min}min') ts_index = pd.date_range(t_start, t_end, freq=f'{freq_min}min', inclusive='left') expand_rows = [] for ts in ts_index: seg_start = pd.Timestamp(ts) seg_end = seg_start + pd.Timedelta(minutes=freq_min) # 与订单时段求交集时长 overlap_min = (min(seg_end, row['end_time']) - max(seg_start, row['start_time'])).total_seconds() / 60 if overlap_min > 0: expand_rows.append({ 'start_time': seg_start, 'energy_seg': power_kw * (overlap_min / 60), 'station_id': row['station_id'] }) return expand_rows expanded = [] for _, r in df.iterrows(): expanded.extend(expand_order(r)) # 聚合成站级15分钟负荷 load_15min = ( pd.DataFrame(expanded) .groupby(['station_id', 'start_time'])['energy_seg'] .sum() .reset_index() .rename(columns={'start_time': 'time', 'energy_seg': 'load_kwh'}) )这里用了「平均功率恒定」的近似,是因为订单流水通常只记录总电量和总时长,给不出真实的分钟级功率曲线。对于预测任务来说,这个近似的误差在可接受范围内;但如果你要做的是日内峰谷套利这种对功率曲线极度敏感的任务,就得从充电桩管理平台拿原始功率序列,不能靠订单反推。参数上,freq_min设为15分钟是比较稳妥的默认值,设为5分钟会让序列稀疏性大增,后期补值成本高;设为60分钟则会直接抹掉短时高峰,预测结果过于平滑。
3.3 外部特征拼接:时间特征与气象特征的三大对齐原则
聚合出负荷序列后,需要把时间特征和环境特征拼到同一张表上。我习惯在DataFrame里生成三类时间特征:小时、星期、是否节假日,再加上距离最近节假日的天数。充电负荷的周周期性非常强,工作日早高峰和周末午后是完全不同的形态,所以小时和星期这两个特征必须同时存在,只给其中任何一个都会丢失关键模式。
气象数据对齐有三个原则:第一,只能使用「预测时刻已知」的信息,即温度、降水等应从历史观测或预报值中取,不能用当天最终实测值去预测当天的负荷,否则在线上推理时会拿不到同期的数据;第二,日级气象数据要向前填充到15分钟级,不能向后填充,因为当天午间负荷不可能携带晚上才产生的气象信息;第三,对雨雪天气的标记不宜只用一个布尔值,建议拆成「是否有雨」「降水量等级」「是否极端天气」三个字段,因为小雪和暴雨对充电行为的影响差异极大。
写到这里要特别提醒一点:环境特征拼接最容易出现的脏数据问题是时区错位。有些气象站的时间戳用的是UTC,而充电订单用的是本地时间,直接合并会产生8小时的偏移,这个错误在特征重要性分析里很难暴露,但会让模型在晨峰时段的预测系统性偏小。合并前务必统一时区。
4. 数据集质量验证:怎么判断一份充电负荷数据集能不能用于建模
4.1 可视化探查的三张必画图
拿到构建好的数据集之后,不要急着训练,先画三张图确认数据形态。第一张是「周负荷热力图」,横轴是小时、纵轴是星期,颜色代表平均负荷;这张图能直观看出工作日与周末的形态差异、早晚高峰时段是否清晰。第二张是「单站15分钟负荷时序图」,选一个连续30天的窗口,肉眼检查是否存在异常跳零或持续为负的值;跳零通常意味着采集断档,持续为负则是电量累加逻辑错误。第三张是「订单SOC分布直方图」,确认进站SOC的分布是否符合运营直觉——如果大量订单集中在0.95以上,说明清洗没生效或原始数据本身就有系统性偏差。
这三张图不需要画得多精致,但一定要看。我在某次模拟项目X中就遇到过一种情况:热力图显示下午3点负荷异常低,排查后发现是有三四天站点设备离线,缺失值被填充成了0,而不是NaN。如果直接拿这份数据训练,模型会把下午3点学成「低负荷时段」,真实运行中这个时间段的预测就会一路偏低。
4.2 缺失率与连续缺失段统计
充电站数据集的缺失问题比普通时间序列更隐蔽,因为站点可能因检修、断电、网络故障而连续缺失数小时甚至数天。做一个简单的统计脚本,输出每个站点的缺失率、最长连续缺失段、缺失时段分布,基本就能判断数据能否直接使用。
# 统计站点缺失率与最长连续缺失 full_index = pd.date_range(load_15min['time'].min(), load_15min['time'].max(), freq='15min') def missing_stats(station_df): # 按完整时间索引补全,缺失的负荷记录为NaN station_df = station_df.set_index('time').reindex(full_index) missing_mask = station_df['load_kwh'].isna() # 连续缺失段长度 missing_runs = 0 max_run = 0 for is_missing in missing_mask: if is_missing: missing_runs += 1 max_run = max(max_run, missing_runs) else: missing_runs = 0 return { 'missing_rate': missing_mask.mean(), 'max_missing_run': max_run, 'total_missing': missing_mask.sum(), } for sid in load_15min['station_id'].unique(): stats = missing_stats(load_15min[load_15min['station_id'] == sid]) if stats['missing_rate'] > 0.05: print(f'站点 {sid} 缺失率 {stats["missing_rate"]:.2%}, ' f'最长连续缺失 {stats["max_missing_run"]} 个点')这段代码的核心是reindex到一个完整的15分钟时间索引上,用NaN标记缺失。判断标准上,我一般把单站缺失率超过5%就标记为高风险,缺失率超过10%则直接考虑剔除该站点或做专门的缺失插补。连续缺失超过96个点(即24小时)的站点,即使用插补也会引入大量偏差,不建议强行纳入训练集。
还需要注意,缺失不是随机的。充电站断电往往发生在某些固定时段(比如夜间检修),这种「结构性缺失」如果直接做均值插补,会让夜间负荷被人为抬高,从而影响凌晨低谷时段的预测。遇到这种情况,更稳妥的做法是把缺失时段标记为独立的布尔特征,让模型自己去学缺失时段的行为模式。
4.3 数据泄露自查清单
构建数据集的过程中,数据泄露是比模型过拟合更隐蔽的问题。我每次都会按以下清单自查一遍:时间特征里是否包含了未来信息(如当天总电量、当天峰值负荷);气象特征是否用了当日最终实测值中的未来字段;充电订单是否错误地包含了预测时点之后才产生的数据;节假日特征是否正确覆盖了调休日,而不是只按周末判断。
其中调休日这个坑非常典型。很多公开节假日列表只标记法定节假日当天,但中国的调休制度会导致某些周末变成工作日、某些工作日变成休息日。如果数据集不做调休校正,模型在五一、国庆前后的预测会系统性偏差。解决办法也很简单:手工维护一张设定年份的调休日历,包含补班日和工作日变体,然后与节假日列表合并成新的工作日标记。这个改动虽然小,但对预测精度的提升是显著且稳定的。
5. 负荷预测数据集使用的常见坑与排查思路
5.1 订单展开时重复累计电量,导致负荷整体偏高
现象:聚合出的日总电量与运营平台月度账单对不上,偏差维持在20%到40%之间。
原因:展开订单时,每笔订单的能量被重复分配到多个时间区间,但聚合时没有去重;更常见的原因是订单在清洗前就被重复计入,比如同一笔订单因设备重启被记录了两条流水,两条记录的时间略有偏移。
解决:在清洗阶段先按订单唯一标识去重,保留时间最早的一条;然后对展开后的DataFrame做一次按「订单ID+时间区间」的groupby去重校验,确认每个订单在每个15分钟区间内只贡献一次电量。
5.2 站点换桩后负荷曲线出现断层,模型预测值突然偏低
现象:某站点在某个日期之后,负荷整体下降了一个台阶,模型预测持续偏高,训练集和验证集指标却都很正常。
原因:站点进行了充电桩升级或扩容,部分旧桩替换成了新桩,但新桩的功率上报周期与旧桩不一致;又或者站点换了一个运营商平台,新平台只上报部分充电行为。
解决:在构建数据集时,为每个站点维护一张「设备变更日志」,将站点在变更前后的数据分别打上不同的版本标记。训练时可以将站点版本作为外部特征输入,或者按版本段分别建模。如果在实际项目中无法拿到变更日志,就用负荷均值突变检测来辅助定位,通常能发现连续多日同时段负荷均值阶跃。
5.3 节假日特征只用官方节假日表,导致调休日预测失准
现象:国庆前一周的补班日(周六),模型把负荷预测成周末形态,偏差超过30%。
原因:节假日特征只标记了假期当天,未处理周末调休为工作日的场景。
解决:把自定义调休日历做成一个独立的csv,包含日期、是否工作日、是否节假日三列,每次建模前读取并与主表合并。这个文件需要每年更新一次,更新的成本很低,但收益非常直接。
5.4 气象数据与充电订单时区未统一,晨峰预测系统性偏移
现象:每日早高峰7点到9点的预测值整体偏低,但其他时段误差正常。
原因:气象数据的UTC时间与本地时间未对齐,气象特征中的温度、降水被错误地平移了数小时,导致模型学到的温度-负荷关系在时间轴上错位。
解决:在拼接前对气象数据做显式的本地化处理,确认时区偏移量,并用一个断言核对特征与负荷的时间索引是否完全一致。这个坑在跨地域数据集里尤其常见,不同的气象源默认时区不一样,绝不能假设所有源都是同一标准。
5.5 缺失值插补用均值填充,把结构性缺失学成了常态
现象:训练指标良好,但实际站点某区域突然断电时,预测值只在断电初期下降,之后又回升到正常水平。
原因:均值插补让模型把断电时段当成「略低于平均负荷但持续存在」的常态,真实的断负荷状态在训练数据里从未出现过。
解决:对连续缺失超过一定长度的时段,用专门的缺失标记特征来替代数值插补,让模型识别「此刻处于异常状态」。同时在评估时,把含缺失插补的样本单独分出来统计误差,不要混在整体指标里。
6. 用数据集反哺模型:从站点负荷到充电行为模拟的进阶技巧
数据集的价值不止于训练一个负荷预测模型。对我来说,数据积累到一定程度后的一个进阶用法是,把订单级的充电行为特征抽出来,建设一个「行为模拟器」,用来生成新站点在只有少量历史数据时的合成负荷序列。
具体做法是:从已有的干净数据集中提取不同站点类型(商圈快充站、居民区慢充站、高速服务区站)的SOC起点分布、充电时长分布、到达时间分布、充电功率分布,然后用蒙特卡洛采样生成合成订单流,再按前面说的展开聚合流程生成负荷序列。这个模拟器的主要用途有两个:一是新站点的负荷预测冷启动问题,没有历史数据时,用同类型站点的行为分布先跑一版模拟负荷;二是做有序充电策略仿真,在模拟负荷上叠加不同的调度策略,评估削峰填谷的效果。
用模拟器生成的负荷序列替代真实数据做模型预训练,再用新站点的少量真实数据做微调,这个流程在冷启动场景里效果很好。我习惯的做法是:模拟器生成约90天的15分钟粒度负荷数据作为预训练集,新站点实际运行一到两周后,拿这两周的数据对模型做增量微调。要注意的是,模拟数据不能替代真实数据做最终效果验证,它只能用于模型初始化和策略预演,最终上线前必须用真实数据做一次完整的回测。
做这个方向几年,最大的感悟是:负荷预测模型的精度上限,在你整理完数据集的那一刻就已经被决定了。你可以花时间调网络结构、调超参、换损失函数,但都不如把数据层的坑先填平来得实在。希望这篇笔记能让你在构建和使用充电站负荷数据集时少走一些弯路。
本文还有配套的精品资源,点击获取