首页 > 编程语言 >【Python】基于非侵入式负荷检测与分解的电力数据挖掘

【Python】基于非侵入式负荷检测与分解的电力数据挖掘

时间:2023-10-25 12:32:29浏览次数:47  
标签:plt file Python glob 负荷 test pd 数据挖掘 csv

前言 本案例将根据已收集到的电力数据,深度挖掘各电力设备的电流、电压和功率等情况,分析各电力设备的实际用电量,进而为电力公司制定电能能源策略提供一定的参考依据。更多详细内容请参考《Python数据挖掘:入门进阶与实用案例分析》一书。 一、案例背景 为了更好地监测用电设备的能耗情况,电力分项计量技术随之诞生。电力分项计量对于电力公司准确预测电力负荷、科学制定电网调度方案、提高电力系统稳定性和可靠性有着重要意义。对用户而言,电力分项计量可以帮助用户了解用电设备的使用情况,提高用户的节能意识,促进科学合理用电。

在这里插入图片描述 二、分析目标 本案例根据非侵入式负荷检测与分解的电力数据挖掘的背景和业务需求,需要实现的目标如下。 分析每个用电设备的运行属性。 构建设备判别属性库。 利用K最近邻模型,实现从整条线路中“分解”出每个用电设备的独立用电数据。 三、分析过程 详细的分析过程可以看下图所示,从数据来源到数据最后准备,最后到性能度量所有的过程。

在这里插入图片描述 四、数据准备 4.1 数据探索 在本案例的电力数据挖掘分析中,不会涉及操作记录数据。因此,此处主要获取设备数据、周波数据和谐波数据。在获取数据后,由于数据表较多,每个表的属性也较多,所以需要对数据进行数据探索分析。在数据探索过程中主要根据原始数据特点,对每个设备的不同属性对应的数据进行可视化,得到的部分结果如下图1~图3所示。

添加图片注释,不超过 140 字(可选) (图1 无功功率和总无功功率)

添加图片注释,不超过 140 字(可选) (图2 电流轨迹)

添加图片注释,不超过 140 字(可选) (图3 电压轨迹) 根据可视化结果可以看出,不同设备之间的电流、电压和功率属性各不相同。 对数据属性进行可视化如代码清单1所示。 import pandas as pd

import matplotlib.pyplot as plt

import 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)

4.2 缺失值处理 通过数据探索,发现数据中部分time属性存在缺失值,需要对这部分缺失值进行处理。由于每份数据中time属性的缺失时间段长不同,所以需要进行不同的处理。对于每个设备数据中具有较大缺失时间段的数据进行删除处理,对于具有较小缺失时间段的数据使用前一个值进行插补。 在进行缺失值处理之前,需要将训练数据中所有设备数据中的设备数据表、周波数据表、谐波数据表和操作记录表,以及测试数据中所有设备数据中的设备数据表、周波数据表和谐波数据表都提取出来,作为独立的数据文件,生成的部分文件如图 4 所示。

添加图片注释,不超过 140 字(可选) (图4 提取数据文件部分结果) 提取数据文件如代码清单 2 所示。

将xlsx文件转化为CSV文件

import glob

import pandas as pd

import 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_col=0, sheet_name=None)

    for key in combine1:

        combine1[key].to_csv('../tmp/' + file[8: -5] + key + '.csv', encoding='utf-8')

print('处理完成')

xls_list = ['../data/附件1/.xlsx', '../data/附件2/.xlsx']

file_transform(xls_list[0]) # 处理训练数据

file_transform(xls_list[1]) # 处理测试数据

提取数据文件完成后,对提取的数据文件进行缺失值处理,处理后生成的部分文件如图 5 所示。

添加图片注释,不超过 140 字(可选) (图5 缺失值处理后的部分结果)

对每个数据文件中较大缺失时间点数据进行删除处理,较小缺失时间点数据进行前值替补

def missing_data(evi):

print('共发现%s个CSV文件' % len(glob.glob(evi)))

for j in glob.glob(evi):

    fr = pd.read_csv(j, header=0, encoding='gbk')

    fr['time'] = pd.to_datetime(fr['time'])

    helper = pd.DataFrame({'time': pd.date_range(fr['time'].min(), fr['time'].max(), freq='S')})

    fr = pd.merge(fr, helper, on='time', how='outer').sort_values('time')

    fr = fr.reset_index(drop=True)



    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], axis=1)

    frame = pd.DataFrame(frame.values.T, index=frame.columns, columns=frame.index)

    frames = frame.fillna(method='ffill')

    frames.to_csv(j[:-4] + '1.csv', index=False, encoding='utf-8')

print('处理完成')

evi_list = ['../tmp/附件1/*数据.csv', '../tmp/附件2/*数据.csv']

missing_data(evi_list[0]) # 处理训练数据

missing_data(evi_list[1]) # 处理测试数据

五、属性构造 虽然在数据准备过程中对属性进行了初步处理,但是引入的属性太多,而且这些属性之间存在重复的信息。为了保留重要的属性,建立精确、简单的模型,需要对原始属性进一步筛选与构造。 5.1 设备数据 在数据探索过程中发现,不同设备的无功功率、总无功功率、有功功率、总有功功率、功率因数和总功率因数差别很大,具有较高的区分度,故本案例选择无功功率、总无功功率、有功功率、总有功功率、功率因数和总功率因数作为设备数据的属性构建判别属性库。 处理好缺失值后,每个设备的数据都由一张表变为了多张表,所以需要将相同类型的数据表合并到一张表中,如将所有设备的设备数据表合并到一张表当中。同时,因为缺失值处理的其中一种方式是使用前一个值进行插补,所以产生了相同的记录,需要对重复出现的记录进行处理,处理后生成的数据表如表1所示。

在这里插入图片描述 合并且去重设备数据如代码清单4所示: import glob import pandas as pd import 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', header=None, encoding='utf-8')
datalist = df.drop_duplicates()
datalist.to_csv(file_path[0] + '/device_combine.csv', index=False, header=0)

print('去重完成')

csv_list = ['../tmp/附件1/*设备数据1.csv', '../tmp/附件2/*设备数据1.csv']

combined_equipment(csv_list[0]) # 处理训练数据 combined_equipment(csv_list[1]) # 处理测试数据

5.2 周波数据 在数据探索过程中发现,周波数据中的电流随着时间的变化有较大的起伏,不同设备的周波数据中的电流绘制出来的折线图的起伏不尽相同,具有明显的差异,故本案例选择波峰和波谷作为周波数据的属性构建判别属性库。 由于原始的周波数据中并未存在电流的波峰和波谷两个属性,所以需要进行属性构建,构建生成的数据表如表2所示。

在这里插入图片描述 构建周波数据中的属性代码如代码清单 5 所示:

求取周波数据中电流的波峰和波谷作为属性参数

import glob import pandas as pd from sklearn.cluster import KMeans import os

def cycle(cycle_file):

for file in glob.glob(cycle_file):

    cycle_YD = pd.read_csv(file, header=0, encoding='utf-8')
    cycle_YD1 = cycle_YD.iloc[:, 0:128]
    models = []

    for types in range(0, len(cycle_YD1)):

        model = KMeans(n_clusters=2, random_state=10)
        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(axis=0, ascending=True, by=[0])
        mean = pd.concat([mean, r.reset_index(drop=True)], axis=1)

    mean = pd.DataFrame(mean.values.T, index=mean.columns, columns=mean.index)
    mean.columns = ['波谷', '波峰']
    mean.index = list(cycle_YD['time'])
    mean.to_csv(file[:-9] + '波谷波峰.csv', index=False, encoding='gbk ')

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, header=0, encoding='gbk')
    means = pd.concat([means, mean0])

file_path = os.path.split(glob.glob(cycles_file)[0])
means.to_csv(file_path[0] + '/zuhe.csv', index=False, encoding='gbk')

print('合并完成')

cycles_file = ['../tmp/附件1/*波谷波峰.csv', '../tmp/附件2/*波谷波峰.csv']

merge_cycle(cycles_file[0]) # 训练数据 merge_cycle(cycles_file[1]) # 测试数据

六、模型训练 在判别设备种类时,选择K最近邻模型进行判别,利用属性构建而成的属性库训练模型,然后利用训练好的模型对设备1和设备2进行判别。构建判别模型并对设备种类进行判别,如代码清单 6 所示。 import glob import pandas as pd from sklearn import neighbors import pickle import os

模型训练

def model(test_files, test_devices):

# 训练集

zuhe = pd.read_csv('../tmp/附件1/zuhe.csv', header=0, encoding='gbk')

device_combine = pd.read_csv('../tmp/附件1/device_combine.csv', header=0, encoding='gbk')
train = pd.concat([zuhe, device_combine], axis=1)
train.index = train['time'].tolist()  # 把“time”列设为索引
train = train.drop(['PC', 'QC', 'PFC', 'time'], axis=1)
train.to_csv('../tmp/' + 'train.csv', index=False, encoding='gbk')

# 测试集

for test_file, test_device in zip(test_files, test_devices):
    test_bofeng = pd.read_csv(test_file, header=0, encoding='gbk')
    test_devi = pd.read_csv(test_device, header=0, encoding='gbk')
    test = pd.concat([test_bofeng, test_devi], axis=1)
    test.index = test['time'].tolist()  # 把“time”列设为索引
    test = test.drop(['PC', 'QC', 'PFC', 'time'], axis=1)



    # K最近邻

    clf = neighbors.KNeighborsClassifier(n_neighbors=6, algorithm='auto')
    clf.fit(train.drop(['label'], axis=1), train['label'])

    predicted = clf.predict(test.drop(['label'], axis=1))
    predicted = pd.DataFrame(predicted)
    file_path = os.path.split(test_file)[1]

    test.to_csv('../tmp/' + file_path[:3] + 'test.csv', encoding='gbk')
    predicted.to_csv('../tmp/' + file_path[:3] + 'predicted.csv', index=False, encoding='gbk')

    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 所示 。 模型分类准确度: 0.7951219512195122 模型评估报告:

           precision    recall  f1-score   support

     0.0       1.00      0.84      0.92        64

    21.0       0.00      0.00      0.00         0

    61.0       0.00      0.00      0.00         0

    91.0       0.78      0.84      0.81        77

    92.0       0.00      0.00      0.00         5

    93.0       0.76      0.75      0.75        59

   111.0       0.00      0.00      0.00         0

   accuracy                                0.80        205
 macro avg       0.36      0.35      0.35       205

weighted avg 0.82 0.80 0.81 205

计算auc:0.8682926829268293 混淆矩阵如下图所示:

在这里插入图片描述 ROC曲线如下图:

在这里插入图片描述 模型评估如代码清单7所示: import glob import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from sklearn import metrics from sklearn.preprocessing import label_binarize import os import 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, header=0, encoding='gbk')
    predicted = pd.read_csv(predicted, header=0, encoding='gbk')
    test.columns = ['time', '波谷', '波峰', 'IC', 'UC', 'P', 'Q', 'PF', 'label']
    print('模型分类准确度:', clf.score(test.drop(['label', 'time'], axis=1), 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, annot=True, cmap='YlGnBu', fmt='g')

    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'], classes=class_names)
    predicted = label_binarize(predicted, classes=class_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, label='area = %0.2f' % auc)
    plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
    plt.fill_between(fpr, tpr, alpha=0.2, color='b')
    plt.xlim([0.0, 1.0])
    plt.ylim([0.0, 1.05])
    plt.xlabel('1-特异性')
    plt.ylabel('灵敏度')
    plt.title('ROC曲线')
    plt.legend(loc='lower right')
    plt.show()

model_evaluation(glob.glob('../tmp/*model.pkl'), glob.glob('../tmp/*test.csv'), glob.glob('../tmp/*predicted.csv'))

根据分析目标,需要计算实时用电量。实时用电量计算的是瞬时的用电器的电流、电压和时间的乘积,公式如下。

添加图片注释,不超过 140 字(可选) 其中,为实时用电量,单位是0.001kWh。为功率,单位为W。 实时用电量计算,得到的实时用电量如表3所示。

在这里插入图片描述 计算实时用电量如代码清单8所示。

计算实时用电量并输出状态表

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, header=0, encoding='gbk')

    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, header=0, encoding='gbk')

    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, header=0, encoding='gbk')
    test_devi['time'] = pd.to_datetime(test_devi['time'])
    test_devi['实时用电量'] = test_devi['P'] * 100 / 3600
    info_lists = info_lists.merge(test_devi[['time', '实时用电量']],

                                  how='inner', left_on='时间', right_on='time')

    info_lists = info_lists.sort_values(by=['时间'], ascending=True)
    info_lists = info_lists.drop(['time'], axis=1)
    file_path = os.path.split(test_device)[1]
    info_lists.to_csv('../tmp/' + file_path[:3] + '状态表.csv', index=False, encoding='gbk')

    print(info_lists)

cw(glob.glob('../tmp/*test.csv'), glob.glob('../tmp/*predicted.csv'), glob.glob('../tmp/附件2/*设备数据1.csv'))

标签:plt,file,Python,glob,负荷,test,pd,数据挖掘,csv
From: https://blog.51cto.com/bluetata/8016544

相关文章

  • 华为云耀云服务器L实例:初级篇-conda与python环境配置
     华为云耀云服务器L实例是一款可快速部署且易于运维的轻量级云服务器,专为中小企业和入门级开发者打造。它不仅拥有华为云擎天架构的强大性能,还具有多项用户体验优化方案,让用户轻松上手,享受简单上云的乐趣。本产品网址为:https://www.huaweicloud.com/product/hecs-light.html......
  • python win32com加密表格文件;加密目录下的所有表格文件
    需求背景:写一个工具,对指定路径下的所有Excel文件进行加密,设置打开密码和编辑密码实现思路:需要用python遍历指定目录下的所有文件,判断是否是EXCEl文件,还要判断文件是否原本就有密码,加密完成后将结果写入到文本文件代码:importosimporttkinterimporttkinter.filedialogfrom......
  • Python判断多个文件夹的文件夹名是否包含“分公司”或“营销中心”怎么处理?(方法二)
    大家好,我是皮皮。一、前言前几天在Python最强王者群【哎呦喂 是豆子~】问了一个Python自动化办公的问题,一起来看看吧。大佬们请问下 判断多个文件夹的文件夹名是否包含“分公司”或“营销中心” 有没有什么简便的办法可以实现呀?二、实现过程这里【东哥】给了两个示例代码,实现......
  • python往图片上面添加数字
    需求背景:做倒计时图片;实现思路:先准备好一张图片作为背景图,用python往图片上添加天数,保存图片;从0-69天,一共生成70张图片背景图如图:代码如下:#这个程序用来生成70张倒计时图片fromPILimportImage,ImageDraw,ImageFontforiinrange(70):#读取图片img=Im......
  • python--playwright修改GET/POST请求参数,抓包修改数据
    首先,playwright修改GET/POST请求参数后在浏览器(chromium)的network面板的入参是没有变化的,但实际上传给服务端的参数是已经发生变化了的,下面先搭建了一个返回入参的flask服务,地址为"http://127.0.0.1:8083"。接着通过playwright分别发送GET和POST请求,参数均为:{"key1":"value1","......
  • 基于Python的 如何检查字符串输入是否为数字
    一概念这种有很多常用的方法,这里只介绍一种常用的方法是使用正则表达式来匹配数字的模式。通过定义一个匹配数字的正则表达式,然后使用re模块中的search()方法来进行匹配。二例子:下面是一个简单的例子:#示例代码5importreinput_str=input("请输入一个字符......
  • pip安装opencv-contrib-python库报错
    背景介绍:opencv-python是opencv的python代码库,包含一些基本的主要的函数,而opencv-contrib-python可以理解为是opencv-python库的高配版本,它还额外包含一些扩展函数与新研发的正在使用阶段的函数等等。笔者在Windows中使用pycharm建立一个新的虚拟环境,想要安装opencv-contrib-p......
  • Python字符串前缀u、r、b、f含义
    1、字符串前加u例子:u"字符串中有中文"含义:前缀u表示该字符串是unicode编码,Python2中用,用在含有中文字符的字符串前,防止因为编码问题,导致中文出现乱码。另外一般要在文件开关标明编码方式采用utf8。Python3中,所有字符串默认都是unicode字符串。 2、字符串前加r例子:r......
  • 用python计算圆周率PI
    fromrandomimportrandomfrommathimportsqrtimporttimeDARTS=10**7hits=0.0a=1start=time.perf_counter()foriinrange(1,DARTS+1):x,y=random(),random()dist=sqrt(x**2+y**2)ifdist<=1.0:hits=hits+1ifi==DARTS*......
  • Python贝叶斯MCMC:Metropolis-Hastings、Gibbs抽样、分层模型、收敛性评估
     全文链接:https://tecdat.cn/?p=33961原文出处:拓端数据部落公众号在常规的马尔可夫链模型中,我们通常感兴趣的是找到一个平衡分布。MCMC则是反过来思考——我们将平衡分布固定为后验分布:并寻找一种转移核,使其收敛到该平衡分布。岛屿示例首先提供一个示例,以具体展示Metropo......