非侵入式负荷识别:理论、技术与应用,非侵入式电力负荷监测
终极管理员 知识笔记 39阅读
电力数据挖掘 概述案例背景分析目标分析过程数据准备数据探索缺失值处理 属性构造设备数据周波数据模型训练 性能度量推荐阅读

主页传送门 传送
概述摘要本案例将根据已收集到的电力数据深度挖掘各电力设备的电流、电压和功率等情况分析各电力设备的实际用电量进而为电力公司制定电能能源策略提供一定的参考依据。更多详细内容请参考《Python数据挖掘入门进阶与实用案例分析》一书。

为了更好地监测用电设备的能耗情况电力分项计量技术随之诞生。电力分项计量对于电力公司准确预测电力负荷、科学制定电网调度方案、提高电力系统稳定性和可靠性有着重要意义。对用户而言电力分项计量可以帮助用户了解用电设备的使用情况提高用户的节能意识促进科学合理用电。
分析目标本案例根据非侵入式负荷检测与分解的电力数据挖掘的背景和业务需求需要实现的目标如下:
分析每个用电设备的运行属性。
构建设备判别属性库。
利用K最近邻模型实现从整条线路中“分解”出每个用电设备的独立用电数据。
分析过程 数据准备 数据探索在本案例的电力数据挖掘分析中不会涉及操作记录数据。因此此处主要获取设备数据、周波数据和谐波数据。在获取数据后由于数据表较多每个表的属性也较多所以需要对数据进行数据探索分析。在数据探索过程中主要根据原始数据特点对每个设备的不同属性对应的数据进行可视化得到的部分结果如图1~图3所示。
无功功率和总无功功率
电流轨迹
电压轨迹
可视化数据代码示例
import pandas as pdimport matplotlib.pyplot as pltimport os filename os.listdir(../data/附件1) # 得到文件夹下的所有文件名称n_filename len(filename) # 给各设备的数据添加操作信息画出各属性轨迹图并保存def fun(a): save_name [YD1, YD10, YD11, YD2, YD3, YD4, YD5, YD6, YD7, YD8, YD9] plt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签 plt.rcParams[axes.unicode_minus] False # 用来正常显示负号 for i in range(a): Sb pd.read_excel(../data/附件1/ filename[i], 设备数据, index_col None) Xb pd.read_excel(../data/附件1/ filename[i], 谐波数据, index_col None) Zb pd.read_excel(../data/附件1/ filename[i], 周波数据, index_col None) # 电流轨迹图 plt.plot(Sb[IC]) plt.title(save_name[i] -IC) plt.ylabel(电流0.001A) plt.show() # 电压轨迹图 lt.plot(Sb[UC]) plt.title(save_name[i] -UC) plt.ylabel(电压0.1V) plt.show() # 有功功率和总有功功率 plt.plot(Sb[[PC, P]]) plt.title(save_name[i] -P) plt.ylabel(有功功率0.0001kW) plt.show() # 无功功率和总无功功率 plt.plot(Sb[[QC, Q]]) plt.title(save_name[i] -Q) plt.ylabel(无功功率0.0001kVar) plt.show() # 功率因数和总功率因数 plt.plot(Sb[[PFC, PF]]) plt.title(save_name[i] -PF) plt.ylabel(功率因数%) plt.show() # 谐波电压 plt.plot(Xb.loc[:, UC02:].T) plt.title(save_name[i] -谐波电压) plt.show() # 周波数据 plt.plot(Zb.loc[:, IC001:].T) plt.title(save_name[i] -周波数据) plt.show() fun(n_filename)
缺失值处理 通过数据探索发现数据中部分“time”属性存在缺失值需要对这部分缺失值进行处理。由于每份数据中“time”属性的缺失时间段长不同所以需要进行不同的处理。对于每个设备数据中具有较大缺失时间段的数据进行删除处理对于具有较小缺失时间段的数据使用前一个值进行插补。
在进行缺失值处理之前需要将训练数据中所有设备数据中的设备数据表、周波数据表、谐波数据表和操作记录表以及测试数据中所有设备数据中的设备数据表、周波数据表和谐波数据表都提取出来作为独立的数据文件生成的部分文件如图4所示。
提取数据文件代码示例
# 将xlsx文件转化为CSV文件import globimport pandas as pdimport math def file_transform(xls): print(共发现%s个xlsx文件 % len(glob.glob(xls))) print(正在处理............) for file in glob.glob(xls): # 循环读取同文件夹下的xlsx文件 combine1 pd.read_excel(file, index_col0, sheet_nameNone) for key in combine1: combine1[key].to_csv(../tmp/ file[8: -5] key .csv, encodingutf-8) print(处理完成) xls_list [../data/附件1/*.xlsx, ../data/附件2/*.xlsx]file_transform(xls_list[0]) # 处理训练数据file_transform(xls_list[1]) # 处理测试数据
提取数据文件完成后对提取的数据文件进行缺失值处理处理后生成的部分文件如图5所示。
缺失值处理代码示例
# 对每个数据文件中较大缺失时间点数据进行删除处理较小缺失时间点数据进行前值替补def missing_data(evi): print(共发现%s个CSV文件 % len(glob.glob(evi))) for j in glob.glob(evi): fr pd.read_csv(j, header0, encodinggbk) fr[time] pd.to_datetime(fr[time]) helper pd.DataFrame({time: pd.date_range(fr[time].min(), fr[time].max(), freqS)}) fr pd.merge(fr, helper, ontime, howouter).sort_values(time) fr fr.reset_index(dropTrue) frame pd.DataFrame() for g in range(0, len(list(fr[time])) - 1): if math.isnan(fr.iloc[:, 1][g 1]) and math.isnan(fr.iloc[:, 1][g]): continue else: scop pd.Series(fr.loc[g]) frame pd.concat([frame, scop], axis1) frame pd.DataFrame(frame.values.T, indexframe.columns, columnsframe.index) frames frame.fillna(methodffill) frames.to_csv(j[:-4] 1.csv, indexFalse, encodingutf-8) print(处理完成) evi_list [../tmp/附件1/*数据.csv, ../tmp/附件2/*数据.csv]missing_data(evi_list[0]) # 处理训练数据missing_data(evi_list[1]) # 处理测试数据
属性构造 虽然在数据准备过程中对属性进行了初步处理但是引入的属性太多而且这些属性之间存在重复的信息。为了保留重要的属性建立精确、简单的模型需要对原始属性进一步筛选与构造。
设备数据在数据探索过程中发现不同设备的无功功率、总无功功率、有功功率、总有功功率、功率因数和总功率因数差别很大具有较高的区分度故本案例选择无功功率、总无功功率、有功功率、总有功功率、功率因数和总功率因数作为设备数据的属性构建判别属性库。
处理好缺失值后每个设备的数据都由一张表变为了多张表所以需要将相同类型的数据表合并到一张表中如将所有设备的设备数据表合并到一张表当中。同时因为缺失值处理的其中一种方式是使用前一个值进行插补所以产生了相同的记录需要对重复出现的记录进行处理处理后生成的数据表如表1所示。
合并且去重设备数据代码示例
import globimport pandas as pdimport os # 合并11个设备数据及处理合并中重复的数据def combined_equipment(csv_name): # 合并 print(共发现%s个CSV文件 % len(glob.glob(csv_name))) print(正在处理............) for i in glob.glob(csv_name): # 循环读取同文件夹下的CSV文件 fr open(i, rb).read() file_path os.path.split(i) with open(file_path[0] /device_combine.csv, ab) as f: f.write(fr) print(合并完毕) # 去重 df pd.read_csv(file_path[0] /device_combine.csv, headerNone, encodingutf-8) datalist df.drop_duplicates() datalist.to_csv(file_path[0] /device_combine.csv, indexFalse, header0) print(去重完成) csv_list [../tmp/附件1/*设备数据1.csv, ../tmp/附件2/*设备数据1.csv]combined_equipment(csv_list[0]) # 处理训练数据combined_equipment(csv_list[1]) # 处理测试数据
周波数据 在数据探索过程中发现周波数据中的电流随着时间的变化有较大的起伏不同设备的周波数据中的电流绘制出来的折线图的起伏不尽相同具有明显的差异故本案例选择波峰和波谷作为周波数据的属性构建判别属性库。
由于原始的周波数据中并未存在电流的波峰和波谷两个属性所以需要进行属性构建构建生成的数据表如表2所示。
构建周波数据中的属性代码示例
# 求取周波数据中电流的波峰和波谷作为属性参数import globimport pandas as pdfrom sklearn.cluster import KMeansimport os def cycle(cycle_file): for file in glob.glob(cycle_file): cycle_YD pd.read_csv(file, header0, encodingutf-8) cycle_YD1 cycle_YD.iloc[:, 0:128] models [] for types in range(0, len(cycle_YD1)): model KMeans(n_clusters2, random_state10) model.fit(pd.DataFrame(cycle_YD1.iloc[types, 1:])) # 除时间以外的所有列 models.append(model) # 相同状态间平稳求均值 mean pd.DataFrame() for model in models: r pd.DataFrame(model.cluster_centers_, ) # 找出聚类中心 r r.sort_values(axis0, ascendingTrue, by[0]) mean pd.concat([mean, r.reset_index(dropTrue)], axis1) mean pd.DataFrame(mean.values.T, indexmean.columns, columnsmean.index) mean.columns [波谷, 波峰] mean.index list(cycle_YD[time]) mean.to_csv(file[:-9] 波谷波峰.csv, indexFalse, encodinggbk ) cycle_file [../tmp/附件1/*周波数据1.csv, ../tmp/附件2/*周波数据1.csv]cycle(cycle_file[0]) # 处理训练数据cycle(cycle_file[1]) # 处理测试数据 # 合并周波的波峰波谷文件def merge_cycle(cycles_file): means pd.DataFrame() for files in glob.glob(cycles_file): mean0 pd.read_csv(files, header0, encodinggbk) means pd.concat([means, mean0]) file_path os.path.split(glob.glob(cycles_file)[0]) means.to_csv(file_path[0] /zuhe.csv, indexFalse, encodinggbk) print(合并完成) cycles_file [../tmp/附件1/*波谷波峰.csv, ../tmp/附件2/*波谷波峰.csv]merge_cycle(cycles_file[0]) # 训练数据merge_cycle(cycles_file[1]) # 测试数据
模型训练 在判别设备种类时选择K最近邻模型进行判别利用属性构建而成的属性库训练模型然后利用训练好的模型对设备1和设备2进行判别。构建判别模型并对设备种类进行判别如代码清单6所示。
建立判别模型并对设备种类进行判别代码示例
import globimport pandas as pdfrom sklearn import neighborsimport pickleimport os # 模型训练def model(test_files, test_devices): # 训练集 zuhe pd.read_csv(../tmp/附件1/zuhe.csv, header0, encodinggbk) device_combine pd.read_csv(../tmp/附件1/device_combine.csv, header0, encodinggbk) train pd.concat([zuhe, device_combine], axis1) train.index train[time].tolist() # 把“time”列设为索引 train train.drop([PC, QC, PFC, time], axis1) train.to_csv(../tmp/ train.csv, indexFalse, encodinggbk) # 测试集 for test_file, test_device in zip(test_files, test_devices): test_bofeng pd.read_csv(test_file, header0, encodinggbk) test_devi pd.read_csv(test_device, header0, encodinggbk) test pd.concat([test_bofeng, test_devi], axis1) test.index test[time].tolist() # 把“time”列设为索引 test test.drop([PC, QC, PFC, time], axis1) # K最近邻 clf neighbors.KNeighborsClassifier(n_neighbors6, algorithmauto) clf.fit(train.drop([label], axis1), train[label]) predicted clf.predict(test.drop([label], axis1)) predicted pd.DataFrame(predicted) file_path os.path.split(test_file)[1] test.to_csv(../tmp/ file_path[:3] test.csv, encodinggbk) predicted.to_csv(../tmp/ file_path[:3] predicted.csv, indexFalse, encodinggbk) with open(../tmp/ file_path[:3] model.pkl, ab) as pickle_file: pickle.dump(clf, pickle_file) print(clf) model(glob.glob(../tmp/附件2/*波谷波峰.csv), glob.glob(../tmp/附件2/*设备数据1.csv))
性能度量 根据代码清单6的设备判别结果对模型进行模型评估得到的结果如下
混淆矩阵如图7所示
ROC曲线如图8所示
模型评估代码示例
import globimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom sklearn import metricsfrom sklearn.preprocessing import label_binarizeimport osimport pickle # 模型评估def model_evaluation(model_file, test_csv, predicted_csv): for clf, test, predicted in zip(model_file, test_csv, predicted_csv): with open(clf, rb) as pickle_file: clf pickle.load(pickle_file) test pd.read_csv(test, header0, encodinggbk) predicted pd.read_csv(predicted, header0, encodinggbk) test.columns [time, 波谷, 波峰, IC, UC, P, Q, PF, label] print(模型分类准确度, clf.score(test.drop([label, time], axis1), test[label])) print(模型评估报告\n, metrics.classification_report(test[label], predicted)) confusion_matrix0 metrics.confusion_matrix(test[label], predicted) confusion_matrix pd.DataFrame(confusion_matrix0) class_names list(set(test[label])) tick_marks range(len(class_names)) sns.heatmap(confusion_matrix, annotTrue, cmapYlGnBu, fmtg) plt.xticks(tick_marks, class_names) plt.yticks(tick_marks, class_names) plt.tight_layout() plt.title(混淆矩阵) plt.ylabel(真实标签) plt.xlabel(预测标签) plt.show() y_binarize label_binarize(test[label], classesclass_names) predicted label_binarize(predicted, classesclass_names) fpr, tpr, thresholds metrics.roc_curve(y_binarize.ravel(), predicted.ravel()) auc metrics.auc(fpr, tpr) print(计算auc, auc) # 绘图 plt.figure(figsize(8, 4)) lw 2 plt.plot(fpr, tpr, labelarea %0.2f % auc) plt.plot([0, 1], [0, 1], colornavy, lwlw, linestyle--) plt.fill_between(fpr, tpr, alpha0.2, colorb) plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.xlabel(1-特异性) plt.ylabel(灵敏度) plt.title(ROC曲线) plt.legend(loclower right) plt.show() model_evaluation(glob.glob(../tmp/*model.pkl), glob.glob(../tmp/*test.csv), glob.glob(../tmp/*predicted.csv))
根据分析目标需要计算实时用电量。实时用电量计算的是瞬时的用电器的电流、电压和时间的乘积公式如下。
其中为实时用电量单位是0.001kWh。为功率单位为W。
实时用电量计算得到的实时用电量如表3所示。
计算实时用电量
# 计算实时用电量并输出状态表def cw(test_csv, predicted_csv, test_devices): for test, predicted, test_device in zip(test_csv, predicted_csv, test_devices): # 划分预测出的时刻表 test pd.read_csv(test, header0, encodinggbk) test.columns [time, 波谷, 波峰, IC, UC, P, Q, PF, label] test[time] pd.to_datetime(test[time]) test.index test[time] predicteds pd.read_csv(predicted, header0, encodinggbk) predicteds.columns [label] indexes [] class_names list(set(test[label])) for j in class_names: index list(predicteds.index[predicteds[label] j]) indexes.append(index) # 取出首位序号及时间点 from itertools import groupby # 连续数字 dif_indexs [] time_indexes [] info_lists pd.DataFrame() for y, z in zip(indexes, class_names): dif_index [] fun lambda x: x[1] - x[0] for k, g in groupby(enumerate(y), fun): dif_list [j for i, j in g] # 连续数字的列表 if len(dif_list) > 1: scop min(dif_list) # 选取连续数字范围中的第一个 else: scop dif_list[0 ] dif_index.append(scop) time_index list(test.iloc[dif_index, :].index) time_indexes.append(time_index) info_list pd.DataFrame({时间: time_index, model_设备状态: [z] * len(time_index)}) dif_indexs.append(dif_index) info_lists pd.concat([info_lists, info_list]) # 计算实时用电量并保存状态表 test_devi pd.read_csv(test_device, header0, encodinggbk) test_devi[time] pd.to_datetime(test_devi[time]) test_devi[实时用电量] test_devi[P] * 100 / 3600 info_lists info_lists.merge(test_devi[[time, 实时用电量]], howinner, left_on时间, right_ontime) info_lists info_lists.sort_values(by[时间], ascendingTrue) info_lists info_lists.drop([time], axis1) file_path os.path.split(test_device)[1] info_lists.to_csv(../tmp/ file_path[:3] 状态表.csv, indexFalse, encodinggbk) print(info_lists) cw(glob.glob(../tmp/*test.csv), glob.glob(../tmp/*predicted.csv), glob.glob(../tmp/附件2/*设备数据1.csv))
推荐阅读
正版链接
《Python数据挖掘入门、进阶与实用案例分析》是一本以项目实战案例为驱动的数据挖掘著作它能帮助完全没有Python编程基础和数据挖掘基础的读者快速掌握Python数据挖掘的技术、流程与方法。在写作方式上与传统的“理论与实践结合”的入门书不同它以数据挖掘领域的知名赛事“泰迪杯”数据挖掘挑战赛已举办10届和“泰迪杯”数据分析技能赛已举办5届累计1500余所高校的10余万师生参赛为依托精选了11个经典赛题将Python编程知识、数据挖掘知识和行业知识三者融合让读者在实践中快速掌握电商、教育、交通、传媒、电力、旅游、制造等7大行业的数据挖掘方法。
本书不仅适用于零基础的读者自学还适用于教师教学为了帮助读者更加高效地掌握本书的内容本书提供了以下10项附加价值
1建模平台提供一站式大数据挖掘建模平台免配置包含大量案例工程边练边学告别纸上谈兵
2视频讲解提供不少于600分钟Python编程和数据挖掘相关教学视频边看边学快速收获经验值
3精选习题精心挑选不少于60道数据挖掘练习题并提供详细解答边学边练检查知识盲区
4作者答疑学习过程中有任何问题通过“树洞”小程序纸书拍照一键发给作者边问边学事半功倍
5数据文件提供各个案例配套的数据文件与工程实践结合开箱即用增强实操性
6程序代码提供书中代码的电子文件及相关工具的安装包代码导入平台即可运行学习效果立竿见影
7教学课件提供配套的PPT课件使用本书作为教材的老师可以申请节省备课时间
8模型服务提供不少于10个数据挖掘模型模型提供完整的案例实现过程助力提升数据挖掘实践能力
9教学平台泰迪科技为本书提供的附加资源提供一站式数据化教学平台附有详细操作指南边看边学边练节省时间
10就业推荐提供大量就业推荐机会与1500企业合作包含华为、京东、美的等知名企业
通过学习本书读者可以理解数据挖掘的原理迅速掌握大数据技术的相关操作为后续数据分析、数据挖掘、深度学习的实践及竞赛打下良好的技术基础。