用机器学习从电力数据中检测家庭占用状态:项目实战复盘

用机器学习从电力数据中检测家庭占用状态:项目实战复盘 简介针对智能电表与家庭占用率检测场景这份硕士毕业设计项目代码基于 ECO 电耗数据集探索如何通过电力消耗数据预测家庭是否有人占用并专门验证夏季训练模型在冬季数据上的可迁移性。ECO 数据集来自真实家庭用电记录免去额外传感器安装具有低成本、易部署的实用价值。资源面向数据科学、机器学习初学者及智能建筑方向研究者可借鉴其数据预处理、特征工程、模型训练与跨季节评估的完整实现思路。包体十分精简共2个文件包括1个 Python 脚本和1个 Markdown 说明文档压缩包仅8KBPython 脚本涵盖数据加载、特征构建、分类器训练与结果对比README 则补充了项目背景、数据集来源与复现说明方便快速阅读与本地尝试。目前已有241人学习/下载对想了解功耗数据在占空检测中落地应用的小型项目而言是一份清晰、轻量的参考样例。 如果家里的电表能基于电力消耗数据判断出“现在屋里有没有人”很多麻烦都能自动消失白天上班忘了关空调电表检测到无人直接调度离家模式深夜突然出现异常的用电曲线系统能猜测可能有人闯入独居老人的家电规律一旦偏离常态后台也能提前预警。听起来像智能家居的广告但这其实是一个可以靠机器学习认真做的数据科学课题——我在完成数据科学硕士学位时的 Capstone 毕业项目做的就是这件事。这个项目要从零开始准备数据、做特征工程、对比多个模型、最后在真实场景里检验效果。整个过程坑不少但也很有代表性。无论你是正在找毕业设计灵感的数据科学学生还是对时间序列预测、行为识别、智能家居感兴趣的人这篇复盘都值得花几分钟看完。我会把从“为什么用电耗数据”到“怎么做特征、选模型、避坑”的核心环节全部摊开讲包括很多论文里不会写的细节。1. 项目整体设计与思路拆解1.1 这个项目到底在解决什么问题家庭占用检测Household Occupancy Detection的核心问题只有一句话根据已有的电力数据判断某个家庭在某个时间点有没有人。这里“有没有人”不是模糊的概念而是要落到具体的时间粒度上比如每15分钟、每30分钟输出一个状态状态一般就是二分类有人、没人。这个问题背后的实际驱动力主要来自三个场景。第一是智能家居节能全屋无人时自动进入离家模式关掉空调、地暖等高耗电设备电热水器这类大功率电器也可以降低功率待命第二是安防告警家里明明没人用电模式却明显异常说明可能有非授权人员活动系统自动推送通知第三是适老化监护独居老人的用电曲线如果连续几天偏离日常规律说明可能发生了意外需要有人上门确认。从机器学习角度看这个任务的特殊之处在于它不是一个典型的回归预测也不是简单的时间序列预测而更像一个“带时间上下文的分类任务”。你预测的不是未来用电量而是当前的人体状态。用电量只是特征标签是是否有人。同样是晚上8点的一盏灯和凌晨3点的一盏灯背后含义完全不同所以模型必须结合时间上下文、功率变化趋势等信息才能做准。1.2 为什么不用传感器而选择电耗数据开题答辩时老师第一个问题就问到了点子上为什么放着现成的人体传感器不用非要从电表数据里绕一圈传感器方案红外、毫米波雷达、摄像头的优点是准确率高但代价也很明显。摄像头直接劝退很多人——大多数家庭无法接受客厅里有一个一直盯着自己看的镜头红外和毫米波雷达虽然不涉及隐私但容易误报宠物跑过、窗帘飘动、空调出风都可能触发而且传感器需要独立供电、联网、定期换电池和固件维护任何一个环节掉链子整个检测系统就失效了。电耗数据走的完全是另一条路。智能电表已经在大量普及数据在电网侧是持续采集的不需要新增任何硬件也没有隐私争议。做占用检测本质上是把已有的数据做二次挖掘边际成本几乎为零。这也是这个项目最有说服力的地方你用的不是为“检测人类”而设计的传感器而是把日常生活中产生的“数据废气”变成了有价值的行为信号。当然这条路也有自己的难处。总表功率是所有电器叠加出来的“混合声”冰箱、空调、充电器都混在一起不同家庭的电器构成天差地别人的用电行为又非常随机。所以这个方向的研究难点不在“能不能做”而在“怎么做得稳定、做得准”。1.3 问题建模分类粒度、预测窗口与评估口径动手写代码之前有几个关键决定需要先拍板。第一是预测粒度。我对比过1分钟、15分钟、30分钟、1小时四档。1分钟粒度适合做实时报警但标签成本和特征噪声都太大1小时粒度又会吞掉短时离家事件比如下楼取快递半小时模型可能把整个小时都判断为“有人在场”。最后我选了15分钟作为主实验粒度理由是智能家居的自动化动作不需要秒级响应15分钟足够同时特征聚合后信号也更稳。第二是预测方式。我采用“滑动窗口分类”的形式取过去1小时可配置的电力数据预测接下来15分钟该家庭是否有人。这种方式和真实业务最贴合——系统只能根据历史判断当下不能偷看未来。第三是评估指标。类别不平衡是这个任务躲不开的问题一天24小时里大多数家庭无人的时段明显多于有人时段如果只看准确率一个“永远预测无人”的模型就能拿到不错的分数显然没有意义。所以我重点盯着F1分数、召回率和ROC-AUC。安防场景尤其要保召回率宁可多误报几次也不希望家里进了人却没有任何反应。2. 数据探索与特征工程实操2.1 数据来源、字段结构与数据质量检查这次项目我用了两类数据源。第一是公开的家庭电力消耗数据集用来做大样本的初步验证第二是我在征得同意后从几位朋友家的智能插座上补充采样的真实数据用来检验模型在“真正杂乱场景”下的表现。这类数据的标准字段通常包括时间戳、有功功率单位kW或W、无功功率、电压、电流、功率因数有些智能电表还会给出分回路的功率读数。如果你拿到的只是总表数据核心字段基本就是时间戳、总用电量、瞬时功率、电压和电流。UCI上有一个很经典的家庭电力消耗数据集包含2006年到2010年一间独栋住宅逐分钟的全局功率和分回路功率记录做初始实验很合适。数据质量是整个项目里最磨人的环节我第一天就被数据折磨得够呛。第一是时间戳缺失和重复智能电表通信偶发中断一断就是几十分钟直接补零会在特征里制造大量“假无人”信号第二是采样间隔不固定有时隔1分钟有时隔2分钟必须重采样到统一频率第三是功率读数会有瞬时尖峰冰箱压缩机启动瞬间甚至出现几千瓦的毛刺这类点不是真实行为需要用中位数滤波或阈值截断提前处理。一个非常实用的质量检查技巧把整体功率曲线按周分组画出来。正常家庭的曲线应该能明显看出工作日与周末的差异、白天与夜晚的差异。如果某一天曲线突然变成一条直线大概率是采集设备掉线或电表检修要把对应时段标记为异常而不是直接喂给模型。2.2 核心特征从原始功率到高区分度变量把原始功率直接丢给模型通常效果一般真正起作用的是特征工程。我按三个层次构造特征缺一不可。第一个层次是统计特征。在滑动窗口内计算有功功率的均值、标准差、最大值、最小值、四分位数、峰值因子和均方根。这些特征捕捉的是“活动强度”家里有人时功率波动通常更大没人时电器处在待机状态曲线相对平稳。标准差和峰值因子在区分“有人开电视”和“无人待机”时非常有效。第二个层次是变化特征。人在室内的典型行为总是伴随“开启”和“关闭”动作——开灯、开微波炉、关冰箱门。所以前后时间步的功率差值一阶差分、窗口内上升沿事件次数、持续超过一定时长的功率跃迁计数都比静态均值更有区分度。我在实验里做过统计有人时段的“窗口内功率上升沿次数”普遍比无人时段高出一倍以上。第三个层次是时间上下文特征。小时0到23、星期几0到6、是否节假日、是否周末这些变量看起来朴素但对电力行为模式的约束力极强。工作日白天9点到18点基本无人晚上19点到23点基本有人这部分规律光靠功率曲线本身很难完整学到显式把时间特征喂给模型能省下大量学习成本。我在项目中用了一段简洁的Python代码来构造这些特征# 假设 df 为重采样后的分钟级数据索引为 DatetimeIndex df[power_mean] df[active_power].rolling(1h).mean() df[power_std] df[active_power].rolling(1h).std() df[power_max] df[active_power].rolling(1h).max() df[power_diff] df[active_power].diff() df[rising_events] (df[power_diff] 100).rolling(1h).sum() df[hour] df.index.hour df[weekday] df.index.weekday df[is_weekend] df[weekday].isin([5, 6]).astype(int)这里rolling(1h)的处理方式可以保证用历史数据计算特征不会引入未来信息。2.3 时间窗口长度与训练集划分的取舍滑动窗口的长度直接影响特征质量。我试了30分钟、1小时、2小时三种窗口结论很清晰窗口太短特征对偶发的待机波动过于敏感误报率偏高窗口太长又会让模型对“短时离家”不敏感。综合下来1小时窗口最佳既能提供足够的数据量做统计又不会把20分钟的下楼取快递吞成“有人在”。比窗口长度更关键的是训练集和测试集的划分方式。很多新手在这里会犯致命错误把数据随机切分成训练集和测试集。时间序列数据的随机切分等于作弊因为相邻时间点的特征高度相似模型相当于提前看到了答案测试集分数会虚高十几个点。正确做法是按时间顺序切分比如取前70%的时间做训练集后30%做测试集中间留出一段gap例如一周作为缓冲避免训练集尾部的信息泄漏到测试集头部。如果数据跨多个家庭还要额外注意按家庭划分。训练集和测试集如果来自同一家庭测出来的是“记忆能力”而不是“泛化能力”。我之后专门做了一次跨家庭压测这个问题的影响远比想象中严重后文会细讲。3. 模型构建、对比与调参记录3.1 先跑基线逻辑回归与随机森林不管最后用什么模型我强烈建议先跑一个简单的基线。它解决的问题只有一个这个预测难度到底有多大值不值得上复杂模型。逻辑回归作为第一个基线优点是非常快、可解释、能直接看特征权重。我对特征做了标准化后简单调了一轮正则化强度C值测试集ROC-AUC在0.82到0.86之间。这个结果说明电力数据里的确有可学习的占用信号模型能明显区分有人与无人但只靠线性关系还远不够好因为用电行为和状态之间显然是非线性的。随机森林作为第二个基线通常比逻辑回归高一截。我主要调了三个参数树的数量、最大深度、叶子节点最小样本数。树的数量加到300后准确率基本饱和继续加只会增加计算量最大深度限制在10以内叶子节点最小样本数设为20可以有效防止模型记住训练集中的个例。随机森林在测试集上的F1大约0.78AUC大约0.89。随机森林还能输出特征重要性排序这一步务必看一眼。我的实验里排名靠前的特征是窗口内功率标准差、一小时平均功率、上升沿次数和小时间特征。这完全符合直觉功率波动程度和用电事件数量是区分有无人状态的核心线索。3.2 进阶尝试XGBoost与LSTM的对比随机森林之后我继续测了XGBoost和LSTM。XGBoost和随机森林虽然都是树模型但训练逻辑不同随机森林是并行训练多棵树再投票XGBoost是一棵一棵串行地训练每棵新树专门去拟合前面所有树的残差。在这个任务上XGBoost训练时间会比随机森林慢一些但精度更高。我调了学习率0.05、最大深度6、subsample0.8和colsample_bytree0.8并开了早停机制最终验证集AUC从随机森林的0.89提升到0.92以上。LSTM是我最期待也最纠结的模型。它的天然优势是能直接消费原始时间序列不用做手工特征模型自己学时序依赖。但问题也很现实LSTM对数据量要求高、训练慢、调参复杂在小数据集上特别容易过拟合。我先后试了单层LSTM隐藏单元128、双层LSTM以及CNNLSTM的组合。在样本量足够时LSTM的AUC能到0.93左右确实略优于XGBoost但跨家庭迁移时它的稳定性不如XGBoost——训练家庭上表现好换一个家庭就明显掉点。如果你只想要一个能快速上线且稳定的方案我建议优先选树模型可解释性好、调参友好、在数据量小的场景更鲁棒。LSTM更适合数据积累充足、有长期维护模型的工程团队再上。3.3 评估指标与结果复盘每个模型都在同一个按时间切分的测试集上评估我统一看准确率、精确率、召回率、F1和ROC-AUC。在类别不平衡的背景下准确率只做参考核心看F1和AUC。我实验中几个模型的典型结果如下模型准确率召回率F1ROC-AUC逻辑回归76.2%0.730.710.84随机森林80.5%0.770.780.89XGBoost83.1%0.800.820.92LSTM84.0%0.810.830.93必须诚实地说这些数字是在单一家庭、已知环境下的测试结果。拿到全新家庭后所有模型的准确率都会掉5到10个百分点掉得最狠的就是LSTM。所以评估时不能只看测试集分数一定要预留一部分“陌生家庭”数据做压力测试。我同时发现误报预测有人但实际没人大多集中在晚上和凌晨。原因是不少家庭有定时电器比如热水器凌晨保温、冰箱定期除霜这些“无人但有功率波动”的模式很容易骗过模型。一个有效的补救措施是在特征里加入“该时段的历史平均功率”作为对照模型能借此识别出“这是设备自身的节奏而不是人的活动”。4. 常见问题与排查技巧实录4.1 标签噪声人工记录的占用日志不可靠做监督学习标签质量决定模型天花板。我最初请几位朋友记录自家的“真实占用日志”结果问题一大堆出门忘了填、回家忘了填、孩子中途回家没记录、周末时段填得非常随意。坏标签直接体现在训练上——模型精确率和召回率怎么调都上不去因为同一段特征一会儿被标记为有、一会儿标记为无模型被互相矛盾的信号搞晕了。这个问题没有完美解法只能靠工程手段缓解。一个办法是用“宽松标签”替代“精确标签”只有连续多个时间点都记录为有人时才标记为正样本单点记录因为可信度低直接丢弃。另一个办法是先跑一个初步模型把模型输出与人工标签明显冲突的样本挑出来人工逐一复核。这个办法很粗暴但效果显著能救回不少被误标的样本。我后来还在项目文档里记了一条部署经验实际产品中最好采用“弱监督定期校准”的策略。先靠一批人工标签训练初始模型上线后收集用户反馈比如用户在App里看到“有人”标记后修正为“无人”这些修正数据持续回流到训练集系统的准确率会越用越高。4.2 数据分布漂移季节、假期与新电器模型上线后最怕的不是随机噪声而是数据分布漂移。夏天和冬天的用电曲线差异很大冬天功率基线整体升高家里可能全天开着暖气夏天可能白天没人但空调仍在运转容易被误判为“有人”。节假日则完全打破“工作日白天无人”的规律如果训练数据只覆盖某一段时间模型到了其他季节就失灵。我应对漂移的做法有三条。第一在特征里显式加入季节、温度等外部变量前提是能拿到相关数据告诉模型“这是一个寒冷冬天的深夜”而不是让它盲目对比功率绝对大小。第二训练数据尽量覆盖全年各月避免只用某个季节的样本。第三上线后配置监控指标比如每日预测的“有人”比例如果连续几天偏离历史正常范围就要触发重新训练或告警。4.3 跨家庭泛化项目的真正难点项目结尾我做了一个“陌生家庭压测”用A、B、C三家的数据训练模型然后在D家测试。结果很不乐观XGBoost的F1从0.82掉到约0.68LSTM更惨直接掉到0.58。这说明模型记住了训练家庭的电器习惯而不是在学“人用电的通用规律”。要提升跨家庭泛化我试出了几个有效方向。第一是按家庭归一化对每个家庭的功率数据先减去自家均值、再除以自家标准差把绝对功率变成相对功率不同家庭的差异立刻小了很多。第二是构建事件序列代替原始功率曲线只关注开和关的模式而不是某个电器到底用了多少瓦。第三是尝试域自适应方法在多个源家庭上学一个通用表示再用目标家庭少量数据做微调。最后一个方向前期成本高但效果上限也最高。这个项目如果继续往下做还可以加入多模态数据比如门锁日志、WiFi连接设备数、室内光照度等和电耗数据做融合通常能将检测F1再提升5到8个百分点。另一个价值更高的方向是做可解释系统——不仅告诉用户“家里有没有人”还说明“因为冰箱在转、灯没开、功率平稳所以判断没人”。这种透明度对产品化极为重要用户信任度会完全不一样。做这个 Capstone 项目我最大的体会是数据科学里最贵的不是模型而是对业务场景的理解和对数据的敬畏。特征工程比调参重要标签质量比骨架模型重要时序划分比交叉验证重要——这些问题想透了项目成功一半。我的代码已经整理到 MS-Capstone-Project-Detecting-Household-Occupancy-Through-Electricity-Consumption-Data 仓库包含完整的特征工程脚本、模型训练代码和实验记录。如果你也准备做类似的任务记住一个建议先把三分之一的时间花在把数据和标签搞干净上再回头想模型否则再高级的模型也只是在垃圾数据上跳舞。本文还有配套的精品资源点击获取