简介:GEFCOM2014能源负荷预测资料包面向电力行业从业者、高校师生与数据科学学习者,围绕多地区小时级能源负荷数据展开,适合用R完成时间序列分析、预测建模与模型评估的课程练习和课题复现。压缩包约111.53MB,文件总数与主要类型明细上游暂未提供,包体信息以实际下载内容为准。已有1425人学习,该主题在负荷预测教学与研究中具有一定关注度。读者可借助其中的历史负荷数据,结合时间序列对象、可视化、预测与机器学习工具,复现序列分解、ARIMA建模、特征工程、交叉验证、网格调参与集成学习等分析链路,并通过均方误差、均方根误差、平均绝对误差和决定系数等指标,以及预测值与实际负荷对比图、残差图,理解能源消耗模式与预测误差来源。对希望从传统统计模型过渡到机器学习组合方案的读者,这份材料也可作为较完整的案例参考。
1. 面试被问负荷预测却答不上分位数
面试官问“你怎么做负荷预测”,很多人张口就是 LSTM 加注意力。再追问一句预测的是哪个分位数、损失函数怎么算、温度用的是观测还是预报,就答不上来了。GEFCOM2014 能源负荷预测这条线之所以被反复拿来问,是因为它把这三件事一次性摆在同一个任务里:给的是小时级负荷加气象数据,要的是未来一天每个小时的一整套分位数,评分只认 pinball loss。R 里三十行代码就能跑出基线,真正难的是说清楚为什么这么切特征、为什么这么排分位数、为什么这个分数低了。适合正在准备数据挖掘与能源算法岗面试、或者被要求复现一份概率负荷预测基线的人,按考点、问法、答法往下读。
2. 数据口径:三张表对不齐,后面八成工作全废
负荷预测这类题,失分很少失在模型上,多半失在对数据的理解上。面试官给你一段描述、让你说思路,他真正想听的是你有没有先问清楚时间粒度、时区、预测原点和评价口径。这四件事定不下来,后面特征工程做得再花,也是在一个错的任务上刷分。GEFCOM2014 负荷赛道的数据组织方式很典型:一条按小时采样的负荷序列,配上对应区域的温度序列,再叠一层日历信息。看起来简单,坑全在细节里。
2.1 三张表的字段与坑位对照
先把数据拆成三张表来看,思路会清楚很多。负荷表是主角,温度表是最强的外生变量,日历表决定模型在特殊日期上会不会出问题。三张表都要落到同一个时间轴上,任何一张的时间戳有偏移,特征就全错位。
| 表 | 关键字段 | 常见坑 |
|---|---|---|
| 负荷表 | 时间戳、区域标识、负荷值 | 单位是 MW 还是 kW;有无负值或零值;换表、检修造成的异常段 |
| 温度表 | 时间戳、站点、温度 | 观测与预报混在一张表;多站点要不要先聚合;缺测怎么补 |
| 日历表 | 日期、星期、节假日标记 | 周末与节假日不是一回事;调休日的处理;跨年周的编号 |
温度这一项要单独强调。同一个小时,用实测温度做特征和用预报温度做特征,模型表现能差出一大截,而后者才是真实上线时的条件。面试里只要提到温度,主动补一句“训练用观测、验证和上线必须换成同时刻可得的预报值,否则就是未来信息泄漏”,这一句往往比多讲一个模型管用。
关于缺测,处理顺序建议固定成三步:先看缺口长度,短缺口用线性插值或前后同小时均值补,长缺口直接标成缺失让模型自己处理,不要硬填。负荷序列的连续缺失段最好单独标记成一列哑变量,因为大段缺失本身往往对应着某种异常事件,把它抹平反而丢信息。
2.2 预测原点和提前期才是题目的真正边界
同样一份数据,“提前一小时”和“提前一天”是两道完全不同的题。提前一小时,上一个小时的负荷可以直接进特征;提前二十四小时,预测期内所有真实值都不能用,最后一个可观测点就是预测原点。答题时先说清楚这个边界,再说特征,顺序反了就会露怯。
多步预测有两条主流路线,要能各说一句优缺点。递归法只训一个一步模型,然后把预测值当真实值喂回去滚二十四步,实现简单,但误差会累积,越往后越飘。直接法对每个提前期单独训一个模型,第 h 步的目标就是把负荷整体左移 h 步,各步之间互不干扰,代价是模型数量翻倍、样本量被稀释。
提示:面试里被问到选哪种,不要只答“直接法更准”。补一句“提前期短、样本少时递归法更稳;提前期长、有明显的日周期错位时用直接法”,这才是权衡。
还有一条容易被忽略:胜负往往被“跨日”这一步决定。预测原点在晚上,未来二十四小时要跨过凌晨的负荷低谷,这一段是所有模型误差最集中的地方。回答时主动提一句“我会按小时分段看误差,而不是只看全天平均”,会显得你真的跑过。
2.3 面试题演练:拿到数据前半小时做什么
题目大意是“给你一份数年跨度的小时级负荷和对应温度,让你做未来一天的预测,你先做什么”。这题几乎每场都问,标准答法不是列工具,而是列判断顺序。
第一步看时间轴。确认采样是否严格一小时一条,有没有重复时间戳,有没有因为夏令时切换导致的缺一小时或多一小时。这一步不做,后面所有滞后特征都会错位一格,而错一格在负荷预测里是灾难性的。
第二步画三条曲线。全序列看趋势和量级突变,一年看季节性,一周看工作日与周末的形态差异。看图的目的不是美观,是判断要不要做去趋势、要不要分季节建模、要不要按星期类型分组。
第三步查异常。负荷曲线里突然掉到零或翻倍的点,先别急着删,先对一下时间,看是不是节假日、极端天气或计量故障。异常点的处理策略要写进答题里,因为面试官会追问“你凭什么判断它是异常”。
第四步定评价口径。明确要用的是分位数损失还是点误差,是全天平均还是分小时统计,有没有要求某些时段权重更高。口径不定,调参就是瞎调。
第五步才是跑基准。这一步放在最后说,但必须说,因为不跑基准的模型没有说服力。
2.4 三个基准必须先跑出来
任何负荷预测题,先把三个对照做出来,后面的模型提升才有参照系。第一个是季节持续法,直接把上周同一时刻或昨天同一时刻的值搬过来,作为分位数预测时给所有分位数同一个数。这个基准在平稳时段强得离谱,很多复杂模型打不过它。
第二个是相似日平均。按星期类型和月份筛出历史上形态相近的若干天,取同一小时的平均值作为中位数预测,再按历史残差的分位数往外扩。这个方法实现成本低,在节假日附近往往比参数模型稳。
第三个是线性分位数回归。特征只放小时哑变量、星期哑变量和温度的一次项,用 R 的quantreg几行就能拟合。它的作用不是拿冠军,而是告诉你“在只考虑线性和日历效应的情况下,误差能压到多少”,后面所有非线性模型都要跟它比。
这三个基准跑完,你手里就有了三档分数,答辩时被问“你的模型到底好在哪”,可以直接给出增量而不是空谈。很多人栽在这里:只有一个模型、只有一个分数,被追问一句“比持续法高多少”就哑了。
3. 概率预测:分位数、pinball loss 与交叉修正
负荷预测的评分只认分位数损失。这一章是整个考点里最能拉开差距的部分,因为它考的不是你会不会调包,而是你懂不懂“预测一个分布”和“预测一个数”的区别。面试官在这个点上通常会连问三层:分位数是什么、损失怎么算、交叉了怎么办。三层都答得上来,基本就过关了。
3.1 分位数不是置信区间
最常见的错误说法是“我预测了 95% 置信区间”。分位数预测给出的是每个分位点上的条件分位数,0.05 分位和 0.95 分位之间的区间,才勉强可以类比成 90% 区间,而且只有在模型校准良好的前提下才成立。这个区别在面试里必须讲清楚,否则后面聊评估全是错的。
更规范的说法是:对每个预测原点,输出一组单调不减的分位数,τ 从 0.01 到 0.99。τ 越小,说明你愿意在这个点上承担“低估”的风险;τ 越大,说明你在防“高估”。电力系统的调度决策依赖的正是这种不对称性,备用容量看高分位,经济性看中位数,这也是为什么赛题不让你只交一个点预测。
再补一句术语。分位数预测的质量有两个维度:可靠性,也就是实际值的落在各分位数以下的比例是否接近 τ;锐度,也就是分位数之间的带宽是否够窄。只谈其中一个都是片面的,可靠但极宽的预测没有决策价值,窄但系统性偏移的预测会挨罚。这句话说出来,档次立刻不一样。
3.2 pinball loss 手算一遍
这个损失函数的定义很短,但必须能手写。给定真实值 y、预测分位数 q、分位水平 τ,损失是分段线性的:低估的时候按 τ 加权,高估的时候按 1-τ 加权。τ 取 0.9 时,低估的惩罚是高估的九倍,这就是分位数回归偏保守的原因。
# 单个分位数的 pinball loss pinball <- function(y, q, tau) { d <- y - q # 残差 mean(ifelse(d >= 0, tau * d, (tau - 1) * d)) # 低估/高估分别加权 } # 多分位数版本:qmat 行是样本、列是分位数,taus 是分位水平向量 pinball_mat <- function(y, qmat, taus) { stopifnot(nrow(qmat) == length(y), ncol(qmat) == length(taus)) loss <- 0 for (j in seq_along(taus)) { d <- y - qmat[, j] # 第 j 个分位数的残差 loss <- loss + mean(ifelse(d >= 0, taus[j] * d, (taus[j] - 1) * d)) } loss / length(taus) # 对所有分位数取平均 }代码里有两个细节值得说。一是d >= 0的方向,y 大于预测值表示低估,此时乘 τ;反过来是高估,乘 τ-1 得到一个正的量。方向写反了分数会变成负数,这是血泪经验级别的低级错误。
二是最后的length(taus)。赛题口径是整个分位数集合上的平均损失,不是中位数一个点的损失。有些实现只算 τ=0.5,结果分数看着漂亮,实际上完全不可比。参数上还要注意单位:负荷单位是兆瓦时,损失的量纲跟着走,跨区域比较前先做归一化,否则大区域会天然吃亏。
3.3 分位数交叉:为什么会出来,怎么修
独立地对每个 τ 拟合一次分位数回归,得到的曲线不保证单调。0.7 分位的预测值低于 0.6 分位,这就是分位数交叉。成因有两个:样本量不足时各 τ 的估计各飘各的;特征在高维空间里稀疏,不同分位点抓到的有效样本不一样。
修法分三档,答题时按成本从低到高说。最省事的是事后排序,对每个预测原点把 99 个分位数从小到大排一遍,简单粗暴但效果好,代价是破坏了原有的估计结构。第二档是拟合时加单调约束,或改用联合建模的方法一次解出所有分位数。第三档是换模型,用分位数目标函数的梯度提升,天然输出一组可以排序的值。
# 事后排序:每行(一个预测时点)的 99 个分位数强制单调 qmat_sorted <- t(apply(qmat, 1, sort)) # 再算损失,保证评估用的是修过的预测 score <- pinball_mat(y_true, qmat_sorted, taus = seq(0.01, 0.99, by = 0.01))apply里MARGIN = 1是按行操作,sort默认升序,返回后要转置回来才对得上原来的行列。这一步跑完顺手统计一下有多少行发生了交叉,如果比例超过百分之几,说明模型设定本身有问题,光排序是治标。
注意:排序只能修好顺序,修不了偏差。如果 0.9 分位系统性偏低,排完序它还是偏低,只是不再低于 0.8 而已。
3.4 面试题:为什么不能只报 RMSE 和 MAPE
这题是送分题,但答得漂亮不容易。核心逻辑是:点误差指标隐含地假设了对称损失,而负荷预测的下游决策是高度不对称的。低估会造成备用不足,代价远高于高估带来的少量浪费,RMSE 一视同仁地把两者平方相加,把这个结构抹掉了。
第二层理由是指标和任务不匹配。业务方要的是“明天下午三点,我有九成把握负荷不超过多少”,这本质上是在问一个分位数,而 RMSE 优化的条件均值回答不了这个问题。用均方误差训出来的模型,交上去的分位数只能靠残差正态假设硬套,遇到双峰或者偏态就崩。
第三层可以说 MAPE 的具体毛病。负荷在凌晨可能接近零,分母一小,百分比误差就爆掉,一个凌晨的小偏差能把全天 MAPE 拉得很难看。而且 MAPE 对高估的惩罚有上界、对低估没有,这在预测任务里是反直觉的。
如果面试官继续追“那你怎么讲清楚你的模型比别人的好”,答案是分层报告:整体平均分位损失、低分位和高分位分开看、按小时段分开看、再给一条可靠性曲线。四组数字一摆,说服力比一个总数强得多。
3.5 校准与锐度必须一起说
单独讲校准很容易被追问。校准好是指实际覆盖率对得上名义分位,比如 0.9 分位以下应该盖住九成样本。但把所有分位数都拉到极宽也能做到校准,这种预测没有意义。所以要紧接着讲锐度:在保持校准的前提下,带宽越窄越好。
实操上给出一个检查套路:把预测期所有样本按分位数统计实际覆盖率,画一条“名义分位 vs 实际覆盖率”的线,理想情况是贴着对角线。再看平均带宽,也就是 0.95 分位减 0.05 分位的均值。两条一起看,才知道模型是“保守但稳”还是“激进但准”。
4. 特征工程与 R 基线:从三张表到 99 个分位数
这一章把前面说的东西落成可跑的代码。面试里被要求“现场说说你怎么实现”,能报出函数名和参数,比背概念更有说服力。R 在这件事上的优势是分位数回归、时间序列工具和数据处理三件套都在一个环境里,不用来回倒数据。
4.1 特征四件套:滞后、温度、日历、聚合
第一类是滞后特征,也是最有效的一类。日周期用滞后 24 和 48,周周期用滞后 168,这三个几乎必放。要注意的是滞后必须相对预测原点整体平移,不能简单用lag()一把梭,否则在提前 24 小时的设定下,滞后 1 到 23 全都用到了预测期内的真实值,直接泄漏。
第二类是温度特征。原始温度一次项不够,负荷和温度的关系是 U 形的:低温采暖、高温制冷、中间一段平缓。所以要加平方项,或者干脆拆成采暖度日和制冷度日两个变量,以 18 度为基准分别取正负部分。这个拆法比平方项更好解释,面试里讲出来也更有画面感。
第三类是日历特征。小时、星期几用因子形式进模型,月份可以只用季节哑变量。节假日单独一列,并且要和周末区分开,因为节假日的负荷形态更像周日而不是周六,这个细节很多人不知道。
第四类是聚合特征。过去 24 小时的滑动均值、滑动标准差,反映近期水平和波动。滑动窗口必须只覆盖预测原点之前的数据,这一点在代码里最容易写错。
library(dplyr); library(lubridate) build_features <- function(load_df, temp_df, horizon = 24) { d <- load_df %>% mutate(ts = ymd_hms(ts), hour = factor(hour(ts)), wday = factor(wday(ts, week_start = 1)), month = month(ts)) %>% arrange(ts) # 滞后特征:整体右移 horizon,保证只用预测原点前的真实值 for (k in c(24, 48, 168)) { d[[paste0("lag", k)]] <- dplyr::lag(d$load, k) } # 滑动统计:先算滚动量,再右移 horizon 步,避免窗口伸进预测期 roll_mean <- as.numeric(stats::filter(d$load, rep(1 / 24, 24), sides = 1)) d$roll24 <- dplyr::lag(roll_mean, horizon) d$roll_sd <- dplyr::lag(as.numeric(stats::filter(d$load, rep(1 / 24, 24), sides = 1, ersistence <- NULL)), horizon) # 温度特征:一次项 + 制冷/采暖度日,基准取 18 度 d <- d %>% left_join(temp_df %>% mutate(ts = ymd_hms(ts)), by = "ts") %>% mutate(cdd = pmax(temp - 18, 0), hdd = pmax(18 - temp, 0)) d }上面这段里stats::filter的sides = 1表示只用当前和过去的值,是滑动窗口方向的关键参数,改成 2 就会用到未来数据。dplyr::lag的第二个参数是步数,配合horizon一起用,把“预测期内不可见”这条约束写进了代码而不是靠脑子记。
pmax里的 18 是温度基准,实际做的时候要按区域气候调整,南方城市可以试 20 到 22,北方采暖主导的区域可以试 15 到 16。这个参数不建议拍脑袋,用交叉验证扫一遍,或者直接在模型里放分段线性项。
4.2 R 最小基线:从原始表到 99 个分位数
有了特征表,拟合分位数回归就是几行的事。关键是分位水平要一次给全,quantreg::rq支持传入向量形式的tau,内部会逐分位求解,最后返回一个多分位模型对象。
library(quantreg) taus <- seq(0.01, 0.99, by = 0.01) # 赛题常见口径:99 个分位 fml <- load ~ lag24 + lag48 + lag168 + roll24 + cdd + hdd + hour + wday + factor(month) fit <- rq(fml, tau = taus, data = train) # 一次拟出 99 条曲线 qmat <- predict(fit, newdata = test) # 行=样本,列=分位数 qmat <- t(apply(qmat, 1, sort)) # 单调修正rq的默认求解器在多分位数、长样本上会慢,可以用method = "fn"显式指定,样本量特别大时配合抽样。predict返回的矩阵列顺序和taus一致,这一点要确认,否则后面算损失会张冠李戴。
如果线性模型不够,下一步换梯度提升的分位数目标。R 里可以用gbm的distribution = "quantile"配合alpha参数逐分位训练,也可以用支持分位数目标的提升库,思路一样:每个分位数训一个模型,最后统排。工程上要注意,99 个模型训练成本不低,可以只训关键分位(如 0.05 到 0.95 每 0.05 一档),中间插值补齐。
4.3 真题演练:提前 24 小时逐小时出分位数
把题目完整走一遍。设定是:用数年小时级负荷和温度,预测未来 24 小时、每个整点的 99 个分位数。
先切数据。用滚动原点的方式切,训练集截止到 T,验证集是 T+1 到 T+24,然后窗口整体前移 24 小时重复。不要用随机划分,时间序列的随机划分会让模型看到未来,分数虚高到不可信,这个坑几乎人人都踩过。
再定模型结构。直接用 4.2 的线性分位数回归做基线,特征里去掉距离预测原点太近的滞后。因为提前 24 小时,lag24 恰好是同一时刻的昨天,可用;lag1 到 lag23 全部不可用,一条都不能进。
然后拟合、预测、排序、算分。分数按小时拆开看,通常凌晨和傍晚两段的损失最高,前者因为负荷水平低、相对波动大,后者因为爬坡快、形态变化剧烈。把这两个时段的分数单独列出来,答辩时能讲出具体原因。
最后做一次消融。去掉温度特征跑一遍,去掉日历特征跑一遍,去掉滞后跑一遍。三组对比下来,你能明确说出哪个特征贡献最大。经验上温度贡献在过渡季节最明显,日历特征在节假日附近贡献最大,滞后在平稳工作日贡献最大。这套消融思路可以平移到任何预测题上。
4.4 结果不对时按这个顺序排查
分数离谱先别改模型,按顺序查四件事。第一查时间轴,有没有重复时间戳、有没有时区错位、缺失段是否被错误填补。第二查泄漏,把预测期的特征打印出来,逐个确认它们的计算窗口都止于预测原点之前。第三查单位,负荷和温度的量纲是否一致,是否有人把千瓦当成兆瓦。第四查分位数方向,损失函数里低估和高估的权重有没有写反。
这四步能解决绝大多数“模型看起来没问题但分数很差”的情况。真正需要动模型的时候,通常是前三步都干净、基准也跑过了、提升仍然不明显,那时候再考虑非线性、外部变量或者集成。
5. 易错点:五条一眼就被看穿的失分答法
5.1 用随机划分做时间序列验证
错在哪:把全部样本打乱后按比例切训练和验证,然后在验证集上报了一个很漂亮的分数。
为什么错:相邻小时的负荷高度相关,随机划分会让训练集里混进验证时点前后的样本,模型实际上是在“见过答案”的情况下作答。这种泄漏在负荷预测里尤其严重,因为日周期和周周期让邻近样本几乎等价。
怎么答对:明确说用滚动原点或者按时间切块,训练集永远在验证集之前,块与块之间留出至少一个预测期的间隔。如果面试官追问“数据量不够怎么办”,答案是缩短验证窗口、增加折数,而不是退回随机划分。
5.2 温度用观测值却说是预报
错在哪:特征里直接用了对应时刻的实测温度,包括预测期内的实测值。
为什么错:上线时预测期内拿不到实测温度,只能拿到数值预报。用实测训练出来的关系,在真实场景下会因为预报误差而性能骤降,这在答辩里是硬伤。
怎么答对:训练阶段可以用观测温度,但验证和上线必须换成预报温度,并且要把预报误差作为一条独立的误差来源讨论。更严谨的做法是训练时就混入带扰动的温度,让模型对这种不确定性有鲁棒性。
5.3 分位数分别建模后不做单调处理
错在哪:99 个分位数各自拟合,直接交上去,中间出现 0.62 分位低于 0.58 分位的情况。
为什么错:分位数交叉在数学上违反了分位数函数的定义,下游按分位数做决策时会得到自相矛盾的结论。评分时也会被扣,因为交叉往往伴随某些分位的系统性偏移。
怎么答对:先做事后排序保证单调,再统计交叉比例作为模型诊断指标。如果交叉比例高,说明样本或特征不足,考虑联合建模或者降低分位数密度。回答时把“排序是治标、联合建模是治本”这句话带上。
5.4 只报一个平均分,不分层
错在哪:答辩时给一个总体 pinball loss,然后说模型有效。
为什么错:平均分掩盖了结构性差异。高分位和低分位的表现可能完全相反,某些小时段的误差可能是其它时段的数倍。面试官追问一句“凌晨表现如何”就露馅了。
怎么答对:分层报告,至少给三组:按分位段(低、中、高)、按小时段(凌晨、日间、傍晚)、按日期类型(工作日、周末、节假日)。三组数字一摆,你对模型的理解程度立刻显出来。
5.5 节假日直接删或用均值填
错在哪:把节假日样本从训练集里剔除,或者用前后几天的均值替换掉。
为什么错:节假日是真实存在的负荷形态,删掉等于告诉模型“这种日子不存在”,到了节假日预测必然失真。均值填补更糟,它把节假日的特征抹成和工作日一样,模型学不到任何区别。
怎么答对:把节假日保留,加一列类型标记(长假、短假、调休),样本少的时候借相似节日的形态做迁移,或者对节假日单独建一个轻量模型。回答时补一句“节假日样本少但代价高,宁可牺牲一点平均分也要保这一段”,面试官爱听这种取舍。
6. 答题技巧:三分钟把一场竞赛讲成一个方案
面试里讲这类项目,最忌讳从头到尾讲模型。正确的结构是五段:问题定义、数据与特征、模型、评估、结论与取舍。三分钟能讲完,每一段三十秒左右,节奏稳。
问题定义先说清楚预测原点、提前期、输出形式。一句“提前 24 小时,输出每个整点的 99 个分位数”,比十句模型描述都管用,因为它证明你知道自己在解什么题。
数据与特征挑三个讲。滞后特征解决周期性,温度特征解决气象敏感性,日历特征解决特殊日。每个特征配一句“为什么加它”,不要罗列。
模型部分先说基准再说提升。先说三个基准的分数,再说你的模型比基准好了多少。这个顺序会让面试官觉得你的数字可信。
评估部分主动提分层。说清楚整体分数、高低分位差异、误差最集中的时段,再补一句校准和锐度的权衡。这一段是区分度最高的地方。
结论与取舍收尾。说出一个你放弃的优化方向并给出理由,比如“我试过加更多外生变量,但验证集上没有稳定提升,反而增加了维护成本,所以砍掉了”。敢于说“没做”和“不做”,比堆功能更显成熟。
押题方向就三条。一是分位数与损失函数,能手写 pinball loss 并解释权重方向。二是泄漏排查,能说出时间序列里泄漏的三种典型来源。三是基准与消融,能讲清楚提升是相对于谁。这三条覆盖了这类题八成以上的追问。
我自己的习惯是,每次讲这类项目之前,强制走一遍“预测原点在哪、哪些特征在预测期内不可得、基准分数是多少”这三问。有一回省了这一步,被追问温度来源时答不上来,当场卡住。从那以后我每次准备负荷预测的面试材料,都先把这三问写在纸上再开口。希望帮到你。
本文还有配套的精品资源,点击获取