简介:这份资源面向机器学习入门与进阶学习者,聚焦回归算法在家庭用电预测中的完整落地实践,帮助读者理解如何从数据预处理、特征工程到模型训练与评估,构建可用的用电量预测方案。压缩包共4个文件,均为Python脚本,整体约9KB,按编号分步组织,便于对照学习线性回归、多项式回归、决策树回归、随机森林回归与支持向量回归等模型的实现差异。内容涉及缺失值处理、异常值检测、标准化、时间序列特征构造,以及MSE、RMSE、R²等评估指标和交叉验证调参思路,适合作为课程设计、练手项目或算法对比实验的参考代码。目前已有259人学习下载,可帮助读者快速搭建家庭用电预测的实验框架,并在此基础上替换数据或调整模型参数进行扩展。
1. 家庭用电预测:回归算法为什么比分类更值得先跑通
家庭用电预测这件事,很多人第一次接触会以为是个分类问题——预测明天用电多还是少。但真正落地时你会发现,业务方要的是具体数值:明天这个小区大概用多少度电、下个月电费预算多少、储能系统该在几点充放。这就把问题拉回了回归算法的地盘。基于机器学习回归算法实现家庭用电预测,核心链路其实不复杂:把历史用电数据按时间切窗,构造特征,喂给回归模型,输出未来一段时间的用电量。它适合两类人:一类是刚学完线性回归、决策树,想找一个有真实数据、有明确评估指标的练手项目;另一类是做能源管理、智能家居的工程师,需要快速搭一个能跑通、能解释、能迭代的基线。这个方向不需要 GPU 集群,一台普通笔记本就能跑,但坑集中在时间序列的切分方式和特征构造上,后面会逐条拆。
2. 数据到手先别急着 fit:家庭用电数据的三个预处理动作
2.1 时间序列的缺失值和异常值怎么处理
家庭用电数据最常见的形态是一列时间戳加一列有功功率,采样间隔从 1 分钟到 1 小时不等。真实数据里一定会有缺失:电表离线、通信中断、传感器漂移。很多人上来就dropna(),结果把连续几天的数据整段删掉,训练集直接少三成。我一般会先做重采样,把不规则时间戳统一到固定频率,再用插值补缺失。
import pandas as pd import numpy as np # df 至少包含 timestamp 和 power 两列 df['timestamp'] = pd.to_datetime(df['timestamp']) df = df.set_index('timestamp').sort_index() # 统一到 15 分钟频率,取均值聚合 df = df.resample('15min').mean() # 短缺口线性插值,长缺口标记出来 df['power'] = df['power'].interpolate(method='linear', limit=8) df['is_gap'] = df['power'].isna().astype(int) # 用前后 7 天同一时刻的中位数兜底长缺口 df['power'] = df['power'].fillna( df['power'].rolling(window=96*7, min_periods=1, center=True).median() )这段代码的逻辑是:先重采样解决时间戳不规则,再对短缺口做线性插值,超过 8 个点(即 2 小时)的缺口用滚动中位数兜底。limit=8这个参数不是拍脑袋,15 分钟采样下 8 个点对应 2 小时,家庭用电在 2 小时内的变化通常接近线性,超过这个窗口线性假设就不成立了。is_gap这一列别扔,后面做特征时可以告诉模型哪些点是补出来的,避免模型把插值当真实规律学。
异常值处理要克制。用电数据里的尖峰有时候是真实的大功率设备启动,比如空调压缩机、电热水器,直接按 3σ 删掉会把有效信号删没。我的做法是先用物理边界卡一刀:家庭单户有功功率超过 20kW 的基本可以判定为采集错误,先置为缺失再走上面的插值流程。剩下的波动交给模型去学,不要过度清洗。
2.2 构造回归特征:滑窗、滞后和日历变量
回归算法不会自己理解时间,你得把时间信息翻译成特征。最直接的是滞后特征:用过去 N 个时刻的值预测下一时刻。但滞后阶数不是越多越好,家庭用电有很强的日周期和周周期,滞后阶数要覆盖至少一个完整周期。
def build_features(series, lags=(1, 2, 4, 96, 192), rolls=(4, 96)): feat = pd.DataFrame(index=series.index) for lag in lags: feat[f'lag_{lag}'] = series.shift(lag) for win in rolls: feat[f'roll_mean_{win}'] = series.shift(1).rolling(win).mean() feat[f'roll_std_{win}'] = series.shift(1).rolling(win).std() feat['hour'] = series.index.hour feat['weekday'] = series.index.weekday feat['is_weekend'] = (series.index.weekday >= 5).astype(int) feat['target'] = series.values return feat.dropna()lags里 1、2、4 对应 15 分钟、30 分钟、1 小时前的值,96 和 192 对应一天前和两天前同一时刻。rolls里的 4 和 96 分别是一小时和一天的滚动窗口。注意所有滚动特征都用了shift(1),这是为了避免用当前时刻的信息预测当前时刻,也就是数据泄漏。日历变量里hour和weekday是周期性的,直接当数值喂给线性回归会出问题——23 点和 0 点数值上差 23,实际只差 1 小时。如果后面用线性模型,这两个特征要做 sin/cos 编码;树模型可以不管。
2.3 训练集和测试集必须按时间切
这是家庭用电预测里翻车最多的地方。很多人习惯train_test_split(shuffle=True),在时间序列上这是致命的。打乱之后,模型在训练集里见过未来时刻的邻居,测试集指标会好得离谱,上线就崩。正确做法是按时间顺序切,比如前 80% 做训练,后 20% 做测试,中间留一段 gap 防止滞后特征跨边界泄漏。
n = len(feat) train_end = int(n * 0.8) gap = 192 # 两天,覆盖最大滞后阶数 train = feat.iloc[:train_end - gap] test = feat.iloc[train_end:] X_train, y_train = train.drop(columns='target'), train['target'] X_test, y_test = test.drop(columns='target'), test['target']gap=192是因为最大滞后是 192,如果不留 gap,测试集第一个样本的滞后特征会落到训练集最后一段,等于偷看了训练集。这个细节在论文里经常被忽略,但做工程必须卡住。
3. 回归算法选型:从线性回归到梯度提升的取舍
3.1 先跑线性回归和决策树建立基线
选型的第一步不是挑最强的模型,而是建立基线。线性回归和单棵决策树训练快、可解释,能帮你判断特征里到底有没有信号。如果线性回归的 R² 只有 0.3,别急着上 XGBoost,先回去看特征构造是不是漏了关键周期。
from sklearn.linear_model import Ridge from sklearn.tree import DecisionTreeRegressor from sklearn.metrics import mean_absolute_error, r2_score models = { 'ridge': Ridge(alpha=1.0), 'tree': DecisionTreeRegressor(max_depth=8, min_samples_leaf=20, random_state=42) } for name, model in models.items(): model.fit(X_train, y_train) pred = model.predict(X_test) print(name, 'MAE', mean_absolute_error(y_test, pred), 'R2', r2_score(y_test, pred))Ridge的alpha=1.0是正则强度,特征多且共线时调大。决策树的max_depth=8和min_samples_leaf=20是防过拟合的,家庭用电数据噪声大,叶子节点样本太少会学到噪声。这两个基线跑完,你心里就有数了:MAE 大概在什么量级,R² 能不能过 0.7。
3.2 随机森林回归和梯度提升怎么选
热搜里随机森林回归算法出现频率很高,它在家庭用电预测里确实是个稳妥选择:对特征尺度不敏感、能处理非线性、不容易过拟合。但梯度提升类模型(XGBoost、LightGBM)在同等特征下通常能再低 10% 到 20% 的 MAE,代价是调参更麻烦、训练更慢。
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor rf = RandomForestRegressor( n_estimators=300, max_depth=12, min_samples_leaf=10, n_jobs=-1, random_state=42 ) gb = GradientBoostingRegressor( n_estimators=300, learning_rate=0.05, max_depth=4, subsample=0.8, random_state=42 ) for name, model in [('rf', rf), ('gb', gb)]: model.fit(X_train, y_train) pred = model.predict(X_test) print(name, 'MAE', mean_absolute_error(y_test, pred))随机森林的n_estimators=300是起点,再往上收益递减。max_depth=12配合min_samples_leaf=10控制单棵树复杂度。梯度提升的learning_rate=0.05配n_estimators=300是经典的慢学习率多轮迭代组合,subsample=0.8引入随机性防过拟合。如果数据量超过十万行,优先试 LightGBM,训练速度差距很明显。
3.3 评估指标别只看 R²
家庭用电预测的业务方关心的是「预测偏差多少度」,所以 MAE 比 R² 更直观。但 MAE 对尖峰不敏感,尖峰预测错了 MAE 可能只涨一点,实际影响很大。我一般会同时看三个指标:MAE 看平均偏差,RMSE 看大偏差惩罚,MAPE 看相对误差。MAPE 在用电量接近零时会爆炸,所以只在对应用电时段算。
| 指标 | 含义 | 家庭用电场景下的参考值 |
|---|---|---|
| MAE | 平均绝对误差 | 单户 15 分钟粒度下 0.05~0.15 kWh |
| RMSE | 均方根误差 | 通常是 MAE 的 1.2~1.5 倍 |
| MAPE | 平均绝对百分比误差 | 用电高峰时段 8%~15% |
参考值不是标准,是让你判断模型有没有跑偏。如果 MAE 到了 0.5 kWh,先查数据预处理,别急着调模型。
4. 避坑与排查:家庭用电预测里最容易翻车的五件事
4.1 现象:测试集 R² 0.95,上线后预测全错
原因:用了随机切分或者没留 gap,滞后特征把未来信息泄漏进了训练集。解决:按时间切分,训练集和测试集之间留至少等于最大滞后阶数的 gap,切完检查测试集第一个样本的滞后特征是否落在训练集范围内。
4.2 现象:模型在白天预测准,夜间误差翻倍
原因:夜间用电量低且波动小,模型在训练时被白天高功率样本主导,夜间样本权重不足。解决:对目标做对数变换,或者按用电时段分层采样,保证夜间样本在训练集里有足够占比。也可以给样本加权,夜间样本权重调高。
4.3 现象:换了新用户数据,MAE 直接翻三倍
原因:不同家庭的用电模式差异极大,单户数据训练的模型直接迁移到另一户会崩。解决:要么每户单独训练,要么在特征里加入家庭属性(户型、人数、是否有电动车),做多户联合训练时用家庭 ID 做分组交叉验证。
4.4 现象:滞后特征重要性排第一,但去掉后效果没变差
原因:滞后特征和滚动特征高度共线,树模型随机选一个用,重要性被稀释。解决:看特征重要性时结合排列重要性(permutation importance),或者做特征聚类后每组只保留一个代表。
4.5 现象:预测曲线整体平移,形状对但数值偏
原因:目标变量分布偏移,训练集和测试集的均值不一致。解决:检查切分点前后是否有季节性变化,比如训练集覆盖冬季、测试集覆盖春季。如果有,要么做差分,要么在特征里加入月份或温度。
5. 把 MAE 再压 15%:残差修正和滚动重训的实操技巧
基线跑通之后,想再进一步,我一般会从两个方向下手。第一个是残差修正:先用梯度提升跑一版预测,把残差拿出来看,如果残差还有明显的日周期,说明模型没学干净,可以把残差作为新目标再训一个模型,两个模型叠加。第二个是滚动重训:家庭用电模式会随季节漂移,固定模型跑三个月就退化,用最近 30 天数据每周重训一次,MAE 通常能再降 10% 到 15%。
# 残差修正示例 base_pred = gb.predict(X_test) residual = y_test - base_pred # 用同样的特征训残差模型 res_model = GradientBoostingRegressor( n_estimators=150, learning_rate=0.03, max_depth=3, random_state=42 ) res_model.fit(X_train, y_train - gb.predict(X_train)) final_pred = base_pred + res_model.predict(X_test) print('修正后 MAE', mean_absolute_error(y_test, final_pred))残差模型的max_depth=3比主模型浅,因为残差里剩下的信号通常更简单,树太深会过拟合。learning_rate=0.03配 150 棵树是保守配置,残差修正宁欠勿过。
滚动重训的工程实现要注意:每次重训只取最近 N 天数据,N 取 30 到 60 天比较合适,太短学不到周周期,太长引入过时模式。重训频率按数据漂移速度定,家庭用电一般每周一次够用。验证方法是用滚动窗口做时间序列交叉验证,每个窗口训一次测一次,看 MAE 的均值和方差,方差大说明模型不稳定,要回去查数据质量。
我自己踩过最深的坑是早期太迷信模型复杂度,在特征没构造好的情况下反复调 XGBoost 参数,折腾一周 MAE 只降了 0.01。后来把日历特征做对、把 gap 留够,换回随机森林反而效果更好。特征决定上限,模型只是逼近上限的工具。希望帮到你。
本文还有配套的精品资源,点击获取