ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

新能源充电站负荷预测数据集构建:清洗、对齐与特征工程

新能源充电站负荷预测数据集构建:清洗、对齐与特征工程 简介针对新能源充电站负荷预测研究提供了一套结构化数据集涵盖时序用电记录、充电行为特征、气象与假期等环境因素以及站点属性适用于高校师生、算法工程师及电力运营人员搭建负荷预测模型。包体共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_timedatetime充电开始时间用于提取小时、星期、节假日特征end_timedatetime充电结束时间计算停留时长charging_durationfloat实际充电时长分钟stop_durationfloat停留时长减充电时长反映占位行为energyfloat充电电量kWhmax_powerfloat本次充电峰值功率kWsoc_startfloat进站SOC0~1soc_endfloat离站SOC0~1average_powerfloat平均充电功率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)] # 规则3SOC起点在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_min15): # 平均功率近似为订单周期内的恒定功率 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, freqf{freq_min}min, inclusiveleft) expand_rows [] for ts in ts_index: seg_start pd.Timestamp(ts) seg_end seg_start pd.Timedelta(minutesfreq_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(), freq15min) 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分钟粒度负荷数据作为预训练集新站点实际运行一到两周后拿这两周的数据对模型做增量微调。要注意的是模拟数据不能替代真实数据做最终效果验证它只能用于模型初始化和策略预演最终上线前必须用真实数据做一次完整的回测。做这个方向几年最大的感悟是负荷预测模型的精度上限在你整理完数据集的那一刻就已经被决定了。你可以花时间调网络结构、调超参、换损失函数但都不如把数据层的坑先填平来得实在。希望这篇笔记能让你在构建和使用充电站负荷数据集时少走一些弯路。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进