用电数据预测家庭入住状态:数据科学完整实战解析 简介这是数据科学硕士毕业设计项目以ECO电力消耗与占用数据集为基础使用Python实现通过家庭用电量推断房屋占用状态有人/无人的完整方案。项目面向机器学习、特征工程与智能建筑数据分析方向的学生和研究者尤其适合关注利用现有智能电表数据实现非侵入式占空检测的读者。压缩包仅含2个文件一个Python脚本承载数据处理、特征提取与模型训练流程一个Markdown文档记录项目背景、实验设置与结论整体大小8KB轻量易读。目前已有242人浏览学习。读者可以从中看到完整的建模脉络包括时序用电特征的构造、占用预测模型的选择与评估以及夏季训练模型跨季节迁移至冬季时的泛化表现并可直接运行或扩展脚本快速复现实验结果为自己的科研或课程项目提供参考。1. 用用电数据判断家里有没有人这个硕士项目把我带进数据科学实战你可能想不到判断一户人家有没有人住居然不用装摄像头、不用红外传感器只看电表曲线就能猜个八九不离十。这个名为 MS-Capstone-Project-Detecting-Household-Occupancy-Through-Electricity-Consumption-Data 的项目正是一份数据科学方向的硕士毕业设计核心思路是用历史电力消耗数据做二分类预测某个时间段内房子里是否有人。它的本质属于非侵入式负载监测NILM的简化版本不需要进入用户家庭、不需要额外硬件只依赖智能电表或总电表读数。这个项目适合正在做数据科学入门项目、课程设计或者想练手完整数据挖掘流程的人——从数据清洗、特征工程、模型调优到评估一条链路走完能非常直观地理解“原始数据如何变成业务判断”。2. 技术栈与架构设计Python 生态做时间序列二分类的经典骨架2.1 从原始电表读数到入住标签任务定义与数据形态这个项目要解决的并不是“预测未来用电量”而是“根据过去一段时间的用电特征判断当前时段是否有人在家”。任务被建模成监督学习里的二分类问题给定一个时间窗口的电力数据电压、电流、有功功率、无功功率等输出一个标签——有人1或无人0。最典型的数据集形态是 CSV 文件包含以下字段日期、时间、全局有功功率单位千瓦、全局无功功率、电压伏特、全局电流安培、厨房用电功率、洗衣房用电功率、热水器用电功率等。原始数据大概长这个样子2006-12-16,17:24:00,4.216,0.418,234.84,18.4,0.0,1.0,0.0 2006-12-16,17:25:00,5.402,0.436,233.63,23.2,0.0,1.0,0.0这里每一行代表一分钟的采样记录。第 1 列和第 2 列是时间戳第 3 列是整户总有功功率后面依次是分回路功率。需要注意的是很多电表数据会包含缺失值特别是一段时间内电表离线或者读数不稳定会出现?或NaN占位符这是清洗时要处理的第一个问题。2.2 用到的库与模型选型从 pandas 到 scikit-learn 的主线整个项目的技术栈基本围绕 Python 数据科学生态展开。pandas 负责数据加载、时间序列重采样和特征拼装numpy 做数组运算scikit-learn 提供分类模型和评估指标matplotlib / seaborn 用于可视化探索。模型层面最常见的选择是随机森林或梯度提升树比如 XGBoost / LightGBM因为这类表格数据上树模型的表现稳定而且能处理非线性特征关系对特征缩放不敏感。为什么这个项目适合用树模型而不是深度学习因为输入特征通常是人工构造的统计特征均值、峰值、方差等维度不算高样本量在百万级别以内树模型训练效率高、可解释性强还能输出特征重要性方便反推“哪些用电特征最能说明家里有人”。我一般会先用随机森林做 baseline再尝试 LightGBM 提升效果。2.3 项目目录结构与核心流程一份标准的数据科学工程骨架从项目仓库的常用组织方式来看代码大概分成数据加载、特征工程、模型训练和评估几个模块。标准的目录结构可能是MS-Capstone-Project-.../ ├── data/ # 原始数据与处理后的特征数据 ├── notebooks/ # Jupyter 探索性分析与实验记录 ├── src/ │ ├── load_data.py # 读取 CSV、处理日期、清洗缺失值 │ ├── features.py # 特征工程统计特征 时间特征 │ └── train_model.py # 训练、评估、保存模型 ├── models/ # 训练好的模型文件如 .pkl └── README.md # 项目说明与运行指引主流程大体如下读入原始 CSV → 解析时间列 → 过滤异常值 → 对功率序列做滑动窗口统计 → 合并外部标签 → 训练验证集划分 → 模型训练 → 输出分类报告与混淆矩阵。这里最核心的设计决策在于“用什么窗口长度构造特征”窗口太长会滞后窗口太短则噪声大通常我会用 30 分钟到 1 小时之间的窗口。3. 核心模块拆解一个样本从原始电表到模型输出的完整链路3.1 数据加载与清洗把分钟级电表读数变成可用的 DataFrame数据加载是整个流程的第一步也是最容易翻车的地方。很多公开数据集的原始格式并不规整日期和时间拆成两列缺失值可能以?字符串存在。常见的处理方式是合并时间列、统一成 datetime 索引、强制数值列转 float 并替换非法字符。下面是一段典型的加载代码import pandas as pd import numpy as np def load_power_data(csv_path): # 读取原始 CSV注意缺失值在文件中可能以 ? 占位 df pd.read_csv(csv_path, sep;, na_values[?], low_memoryFalse) # 合并日期和时间两列生成统一的 datetime 列 df[datetime] pd.to_datetime( df[Date] df[Time], format%d/%m/%Y %H:%M:%S ) # 将 datetime 设为索引方便后续重采样 df.set_index(datetime, inplaceTrue) # 全局有功功率可能有极端异常值比如瞬时尖峰 df df[df[Global_active_power] 0] return df这段代码做了三件事把?统一替换为NaN把日期和时间拼接成单列 datetime 并设为索引最后过滤掉有功功率为 0 或负数的无效记录。参数说明sep;是因为部分欧洲数据集使用分号作为分隔符na_values[?]指定了缺失标记low_memoryFalse避免混合类型导致读取警告。实际使用中如果原始数据日期格式不一样需要同步修改format参数否则会出现大量解析失败。3.2 构造入住标签用时间规则生成监督信号项目里“是否有人”的标签并不会直接出现在电表数据中需要通过时间规则近似生成。比如可以假设工作日的白天 9:00-17:00 大多数人不在家晚 19:00-次日 7:00 在家周末则全天在家这是一个简化的模拟标签。当然如果有真实入住记录比如智能门锁或人为打卡数据直接合并进来即可。生成标签的代码大概这样def create_occupancy_label(df, home_start_hour19, home_end_hour7): # 默认规则工作日 19:00 到次日 7:00 判定为有人 hour df.index.hour weekday df.index.weekday # 周一0周日6 # 先全部标记为 0无人 label pd.Series(0, indexdf.index) # 周末全天算有人工作日夜晚上算有人 is_weekend weekday 5 is_night (hour home_start_hour) | (hour home_end_hour) label[is_weekend | is_night] 1 return label这段代码的核心逻辑是布尔索引组合(hour 19) | (hour 7)覆盖了跨半夜的时段weekday 5把周六日全部标记为有人。不要小看这个步骤——标签的质量直接决定了模型能学到什么。如果时间规则和真实入住习惯偏差很大比如上夜班的人白天在家睡觉模型效果会断崖式下跌。这也是我认为这个项目里最值得细看的一个设计决策。3.3 特征工程滑动窗口统计量与时间上下文特征工程是这个项目里最出效果的部分。原始数据是 1 分钟一条的功率曲线直接丢给模型的话一是维度太高二是丢失了上下文特征。常见做法是重采样成 15 分钟一个点每个点统计上一小时窗口内的均值、最大值、最小值、标准差、峰均比和差分特征。再加上小时数、是否周末等时间上下文形成最终特征矩阵def build_features(df, label, window_min60): # 将原始分钟数据按 15 分钟聚合 rule 15T df_resample df[Global_active_power].resample(rule).agg( [mean, max, min, std, median] ) # 时间上下文特征小时、星期几 df_resample[hour] df_resample.index.hour df_resample[weekday] df_resample.index.weekday # 滞后特征用前一小时的均值表示趋势变化 df_resample[prev_mean] df_resample[mean].shift(4) # 标签按同样的规则聚合取多数投票 label_resample label.resample(rule).agg(lambda x: int(x.mean() 0.5)) # 去掉聚合后出现的缺失行窗口不够长时的边界效应 df_resample.dropna(inplaceTrue) aligned_label label_resample.loc[df_resample.index] return df_resample, aligned_label这里有几个关键参数rule15T表示 15 分钟聚合window_min60对应统计窗口为 1 小时也就是用 4 个 15 分钟点算统计量。shift(4)是取前一行 4 个周期前的均值也就是前 1 小时的均值用来刻画功率的趋势变化。需要注意dropna会删掉前 4 行因为滞后特征缺失造成的 NaN这是时序特征工程的常规处理但代价是损失少量样本。如果样本量紧张可以改用向前填充或直接删除这些特征。3.4 模型训练与评估随机森林 baseline 与类别不平衡处理入住检测天然存在类别不平衡问题——一天 24 小时里可能只有 8 小时判定为有人无人样本占比更高。如果直接训练模型会倾向于把所有样本预测为无人准确率虚高但实际没意义。解决办法是用class_weightbalanced或使用 SMOTE 过采样。下面是训练代码的核心片段from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report, confusion_matrix # 准备特征与标签 X, y df_resample.drop(label, axis1), df_resample[label] # 按时间顺序切分防止未来信息泄漏 split_idx int(len(X) * 0.8) X_train, X_test X.iloc[:split_idx], X.iloc[split_idx:] y_train, y_test y.iloc[:split_idx], y.iloc[split_idx:] # 随机森林使用平衡类权重 model RandomForestClassifier( n_estimators300, max_depth12, class_weightbalanced, random_state42, n_jobs-1 ) model.fit(X_train, y_train) # 预测与评估 y_pred model.predict(X_test) print(classification_report(y_test, y_pred)) print(confusion_matrix(y_test, y_pred))这里有一个常见的坑切分数据不能直接用train_test_split(random_state42)因为它是随机打乱的会把未来数据混进训练集造成“数据泄漏”模型在验证集上的表现会虚高。我采用按时间顺序切分用前 80% 的数据训练、后 20% 验证。class_weightbalanced会自动根据类别频率调整权重让少数类有人的误分类代价更高。n_jobs-1是让随机森林并行使用所有 CPU 核心训练速度会快很多。4. 实验评估与常见问题排查模型效果怎么看、踩坑怎么修4.1 评估指标的取舍别只盯着准确率在这个任务里准确率是一个非常有迷惑性的指标。假设样本里 70% 是无人模型全猜无人也有 70% 准确率看起来“表现不错”实际上一点用都没有。正确做法是看精确率、召回率、F1-score特别是针对“有人”这一类别的召回率——漏报家里有人但判成没人比误报没人在家判成有人代价高得多。比如你希望做安防场景的 dormancy detection漏报意味着有人非法入侵却无法被识别。实际运行项目时随机森林在这个任务上的典型结果是总体准确率 85%-92%F1-score 在 0.82-0.88 之间取决于特征工程的好坏。如果特征里包含滞后特征和时间周期特征F1 会明显上浮。另外一定要画出混淆矩阵看看“有人”类别的误判主要发生在什么时段通常都集中在早晨 6:00-8:00 和傍晚 17:00-19:00 这些过渡时段——因为人在这些时间段活动强度变化大功率特征容易与无人时段重叠。4.2 典型踩坑记录三件让我翻过车的事现象一模型在训练集上准确率接近 100%验证集只有 70%。原因没有打乱时间顺序就用了默认的train_test_split随机打乱导致相邻时间点的数据被分到两个集合里模型“记住”了时间邻居的标签。解决方法是改成按时间顺序切分或者使用TimeSeriesSplit。现象二把所有缺失值直接dropna后可用的样本量少了将近四分之一。原因多个特征在不同时间点缺失比如电压字段在某个时间段整体离线行维度上相互叠加导致删得过多。解决方式是按列检查缺失率超过 30% 的列直接删除而不是删行对于单点缺失用前后 5 分钟的均值填充。现象三用 SMOTE 过采样后模型 F1 反而下降。原因SMOTE 在时间序列上会合成出不存在的功率组合比如把凌晨的低功率段和晚上的高功率段插值成“有人”样本这种伪样本干扰了模型判断。解决方式是放弃 SMOTE只用class_weightbalanced或者对“无人”样本做下采样比如每 15 分钟随机保留 1 个。5. 从零跑通整个项目环境配置、运行命令与一手实操记录5.1 环境准备与依赖安装在开始跑项目之前需要先确认 Python 环境。我建议使用 Python 3.9 或 3.10 版本直接创建一个干净的虚拟环境然后安装项目依赖。核心依赖如下pip install pandas numpy scikit-learn matplotlib seaborn如果本地机器性能有限可以先把n_estimators降到 100 甚至 50跑通后再逐步增加。数据量方面这个项目的原始数据动辄几十万到上百万行在普通笔记本上随机森林训练需要 2-5 分钟完全可以接受。不建议在前处理阶段使用过于复杂的特征比如傅里叶变换会显著增加运行时间收益却不一定明显。5.2 运行主脚本从原始 CSV 到评估报告项目如果按模块化方式组织一般会提供一个主入口文件或者 Jupyter notebook。假设主脚本是train_model.py运行流程就是python src/train_model.py --data data/household_power_consumption.csv --output models/rf_model.pkl脚本内部执行的逻辑依次是加载数据load_data.py→ 构造标签create_occupancy_label→ 特征工程build_features→ 时间序列划分 → 随机森林训练 → 保存模型和评估报告。如果一切顺利最终会在终端看到类似下面的输出F1-score (occupied): 0.86 Precision (occupied): 0.88 Recall (occupied): 0.85 Confusion matrix saved to: reports/confusion_matrix.png这时候模型文件rf_model.pkl就保存在models/目录下后续可以直接用joblib.load()加载再对新数据做预测。5.3 关键参数怎么调三个值得动手改的地方窗口长度在build_features中把window_min60改为 30 或 120。窗口越短特征对实时变化的响应越快但噪声越大窗口越长特征越平滑但滞后越明显。做安防场景推荐 30 分钟窗口做能耗分析推荐 60-120 分钟。聚合粒度把rule15T改成5T会得到更多的样本点但特征矩阵的规模会膨胀 3 倍训练时间变长。如果没有明确的业务需求15 分钟是一个平衡点。阈值create_occupancy_label中的home_start_hour和home_end_hour可以根据具体家庭作息调整。比如在校园宿舍场景可以设置晚上 23:00 到次日 6:00在办公室场景可以反转为白天有人。6. 二次开发指南从硕士项目到可用的入住检测服务6.1 改造点一把离线训练变成在线预测接口目前项目是完整的离线训练流程每次预测都要重新加载模型和全量数据。如果想做成实时监测工具可以用 Flask 或 FastAPI 封装一个简单接口接收最近一小时的电表功率序列用build_features构造特征然后调用已保存的模型返回“有人/无人”的概率。这个改造的核心是保持特征顺序一致——上线前一定要用model.feature_names_in_核对输入特征列名否则特征顺序一变结果就全错了。6.2 改造点二升级模型和特征工程的上限如果你的目标是把 F1-score 从 0.85 推向 0.93 以上有几个方向一是给每个时间点加上滑动窗口的一阶差分特征刻画功率的“突变”情况因为有人在家的时段功率变化更剧烈二是换成 LightGBM 并做贝叶斯超参搜索三是加入“上一小时预测结果”作为特征利用时序连续性做平滑。但要注意引入这些特征时尽量别把测试集信息带进训练过程否则评估结果会虚高。6.3 改造点三扩展到其他用电场景这个项目的框架并不只限于家庭入住检测。把标签生成逻辑替换成“是否有电器在运行”比如空调、热水器就是一套通用的设备使用状态监测方案。把窗口统计和滞后特征组合保留下来换一些业务特征就能快速迁移到店铺客流判断、充电桩使用状态预测等场景。这也是我认为这个项目价值最大的一点——它把时间序列二分类的完整套路讲透了后续换数据、换标签都是举一反三的事。从那以后我每次做时间序列相关的分类任务都会强制走一遍这套流程先做时间感知的切分再用滞后特征验证是否有效最后盯着混淆矩阵看过渡时段到底错在哪里。希望这篇拆解能帮你在跑通这个项目的同时真正理解用电数据里藏着的那些规律。本文还有配套的精品资源点击获取