背景与挖掘目标
传统防窃电主要通过 定期巡检/定期校验电表/用户举报 等方法发现,成本高效果差
现在很多供电局通过、营销稽查人员/用电检查人员和计量工作人员 利用计量异常报警功能和电能量数据查询功能开展用电情况在线监控
通过采集电量异常/负荷异常/终端报警/主站报警/线损异常 等信息,建立数据分析模型,实时检车窃漏电情况。
根据报警时间发生前后客户计量点有关的 电流/电压/负荷 数据,构建基于指标加权的用电异常分析模型,检查用电异常(窃漏电和计量装置故障等)问题。
以上方法能获得用电异常信息,但由于模型误报或漏报过多,无法达到真正快速精确定位异常用户的目的。
且采用这种方式建模时,模型各输入指标权重需要用专家知识和经验主关判断,效果比较差。
现有电力计量自动化系统能够采集到各项 电流/电压/功率 等用电负荷数据及用电异常等终端报警信息,反映用户的用电情况,同时稽查人员业会通过在线稽查系统和现场稽查结合找出异常用户并录入系统。
如果通过这些数据信息提取出窃漏蒂娜用户的关键特征,构建异常用户识别模型,就能自动检查/判断用户是否存在窃漏电行为
本次数据挖掘建模目标如下:
- 归纳出异常用户的关键特征,构建异常用户的识别模型
- 利用实时监测数据,调用异常用户识别模型实现实时诊断
分析方法与过程
窃漏电用户在电力计量自动化系统的监控大用户中只占一小部分。
某些大用户不可能存在窃漏电行为,如:银行/税务/学校/工商等非居民类别,数据预处理时有必要剔除这些用户类别
用电负荷不能直接体现出用户的窃漏电行为
终端报警存在很多误报和漏报
故需要进行数据探索和预处理,总结异常用户的行为规律,再从数据中提炼描述异常用户的特征指标
最后结合历史异常用户信息,整理出识别模型的专家样本数据集,再进一步构建分类模型,实现异常用户的自动识别
异常用户识别流程
- 业务系统
- 选择性抽取
- 每天实时抽取
- 数据抽取
- 选择性抽取:历史数据
- 实时抽取:实时诊断数据
- 数据探索与预处理(数据探索分析)
- 数据清洗
- 缺失值处理
- 数据变换
- 建模和诊断
- 建模样本数据
- 模型训练
- 模型评价
- 预处理后诊断数据
- 自动诊断
- 建模样本数据
- 结果和反馈
- 诊断结果
- 模型优化与重构
- 从电力计量自动化系统/营销系统选择抽取部分大用户用电负荷/终端报警及违约处罚信息等原始数据
- 对样本数据进行探索分析,剔除不可能存在异常行为的行业的用户(白名单用户),初步审视正常用户和异常用户的特征
- 对样本数据进行预处理,包括数据清洗/缺失值处理和数据变换
- 构建专家样本集
- 构建异常用户识别模型
- 在线检测用户用电负荷及终端报警,调用模型实现实时诊断
数据抽取
从营销系统抽取如下数据
- 用户基本信息:用户名词/编号/地址/类别/报装容量/计量方式/电流互感器变比/电压互感变比
- 违约处理记录
- 计量方法及依据
从计量自动化系统抽取如下数据
- 实时负荷:时间点/计量点/总有功功率/A B C相有功功率/A B C相电流/A B C相电压/A B C相功率因数
- 终端报警
为尽量覆盖各种异常方式,样本数据要包含不同用电类别的所有异常用户及部分正常用户。
异常用户的异常开始和结束时间是表征窃漏电的关键时间节点,这些时间节点熵用电负荷和终端报警等数据会有特征变化,抽取样本数据时无比包含关键时间节点前后一定范围的数据,并通过用户负荷数据计算出当天用电量:公式:$f_{l}=0.25 \sum_{m_{i} \in l_{\mathcal{天}}} m_{i}$
- fl为第l天的用电量,mi为第l天每隔15分钟的总有功功率,对其累加求和得到当天用电量
基于此,本案例抽取某市近5年来所有窃漏电用户有关数据和不同用电类别正常用户共208个用户数据,时间20090101-20141231,同时包含每天是否有异常情况的标识
数据探索分析
通过对数据的初步研究,发现数据内在规律特征,有助于旋转合适的数据预处理和数据分析技术。
本例主要采用分布分析和周期性分析等方法对电流数据进行探索分析
- 分布分析
对5年内所有异常用户进行分布分析,统计各个用电类别的且漏电用户分布情况,图中发现非居民类别不存在异常情况,故后面不考虑非居民类别用电数据
- 周期性分析
随机抽取一个正常用户和一个窃漏电用户,采用全后期分析对用电量进行探索
- 正常用电电量探索分析
- 该用户用电量比较平稳,没有太大波动(呈现明显以周为周期的规律)
- 窃漏电用电电量探索分析
- 该用户用电量呈现明显下降趋势,这就是用户异常用电的电量指标特征
结论:正常用电到且漏电过程是用电量持续下降的过程,该用户从2014年9月1日起用电量持续下降,这是用户开始且漏电时表现出来的重要特征
数据预处理
数据清洗
- 原始数据不是所有数据都需要进行分析,需要在数据处理时,将多余数据进行过滤
- 用电类别中,非居民用电类别不存在且漏电现象,需要将非居民用电类别数据过滤掉
- 节假日用电量和工作日比,明显偏低,为了达到较好的数据效果,过滤节假日的用电数据
缺失值处理
- 为达到较好的建模效果,需要对缺失值进行处理,本例采用拉格朗日插值法对缺失值进行插补
选取数据中部分数据做实例,下表是三个用户一个月工作日的电量数据,对缺失值进行插补
数据变换
通过电力计量系统采集的电量/负荷,虽然能一定程度上反映用户异常行为规律,但作为构建模型的专家样本,特征不明显,需要重构,
基于数据变换得到新评价指标来表征异常行为具有的规律
且漏电评价指标体系
- 电量趋势下降指标
- 用电量趋势
- 线损指标
- 线损增长率
- 告警指标
- 与且漏电相关的终端告警数
构建专家样本
对2009年0101 - 2014年1231所有且漏电和正常用户的电量/告警/线损数据和该用户当天是否异常的标识,按且漏电评价指标进行处理并选取其中291个样本数据,得到专家样本库
模型构建
- 构建且漏电用户识别模型
专家样本准备完成后,划分测试集和训练集,随机选取20%做测试样本。
且漏电用户识别课通过构建分类预测模型实现,常用的有LM神经网络和CART决策树,我们分别使用这两种模型并从中选择最优分类模型
模型输入特征包括:电量趋势下降指标/线损类指标/告警类指标,输出项为且漏电标识
(1)数据划分,20%测试集,80%训练集
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
载入数据
前三列为特征,最后一列为标签
data = pd.read_excel('data/power_system.xlsx')
data.head().append(data.tail())
| 电量趋势下降指标 | 线损指标 | 告警类指标 | 是否窃漏电 | |
|---|---|---|---|---|
| 0 | 4 | 1 | 1 | 1 |
| 1 | 4 | 0 | 4 | 1 |
| 2 | 2 | 1 | 1 | 1 |
| 3 | 9 | 0 | 0 | 0 |
| 4 | 3 | 1 | 0 | 0 |
| 286 | 4 | 1 | 2 | 0 |
| 287 | 1 | 0 | 2 | 0 |
| 288 | 5 | 1 | 2 | 1 |
| 289 | 2 | 1 | 0 | 0 |
| 290 | 4 | 1 | 0 | 0 |
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 291 entries, 0 to 290
Data columns (total 4 columns):
电量趋势下降指标 291 non-null int64
线损指标 291 non-null int64
告警类指标 291 non-null int64
是否窃漏电 291 non-null int64
dtypes: int64(4)
memory usage: 9.2 KB
data.describe()
| 电量趋势下降指标 | 线损指标 | 告警类指标 | 是否窃漏电 | |
|---|---|---|---|---|
| count | 291.000000 | 291.000000 | 291.000000 | 291.000000 |
| mean | 2.718213 | 0.512027 | 1.171821 | 0.137457 |
| std | 2.091768 | 0.500716 | 1.065783 | 0.344922 |
| min | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 25% | 1.000000 | 0.000000 | 0.000000 | 0.000000 |
| 50% | 3.000000 | 1.000000 | 1.000000 | 0.000000 |
| 75% | 4.000000 | 1.000000 | 2.000000 | 0.000000 |
| max | 10.000000 | 1.000000 | 4.000000 | 1.000000 |
data.shape
(291, 4)
# 特征
X = data[['电量趋势下降指标', '线损指标', '告警类指标']].values
X.shape
(291, 3)
# 标签
y = data['是否窃漏电'].values
y.shape
(291,)
切分数据集为训练集和测试集
# 建立训练集和测试集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.2, random_state=666)
X_train.shape, X_test.shape, y_train.shape, y_test.shape
((232, 3), (59, 3), (232,), (59,))
使用神经网络建模
使用Keras库建立神经网络模型
设定神经网络输入节点数为3,
输出节点数为1,
隐层节点数为10,
使用Adam方法求解。。。。
对于激活函数,隐藏层使用Relu(x)=max(x, 0)做激活函数
from keras.models import Sequential # 神经网络初始化函数
from keras.layers import Dense, Activation # 层函数,激活函数
Using TensorFlow backend.
model = Sequential() # 建立神经网络
# 第一个隐藏层
model.add(Dense(10, input_shape=(3,))) # 添加输入层(3列特征)到隐藏层(10节点)的连接
model.add(Activation('relu')) # 隐藏层使用relu激活函数
# 输出层
model.add(Dense(1, input_shape=(10,))) # 添加隐藏层(10节点)到输出层(1节点)的连接
model.add(Activation('sigmoid')) #输出层使用sigmoid激活函数(二分类)
WARNING:tensorflow:From c:\programdata\miniconda3\lib\site-packages\tensorflow\python\framework\op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Colocations handled automatically by placer.
# 配置模型
model.compile(
loss='binary_crossentropy', # 损失函数:二分类交叉熵
optimizer='adam', # adam优化器
sample_weight_mode='binary', # 二分类
)
# 训练
model.fit(X_train, y_train, epochs=100, batch_size=1) #训练模型,循环100次,要准确率高需10000次以上
WARNING:tensorflow:From c:\programdata\miniconda3\lib\site-packages\tensorflow\python\ops\math_ops.py:3066: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.cast instead.
Epoch 1/100
232/232 [==============================] - 0s 2ms/step - loss: 0.7772
Epoch 2/100
232/232 [==============================] - 0s 948us/step - loss: 0.5477
Epoch 3/100
232/232 [==============================] - 0s 943us/step - loss: 0.4957
Epoch 4/100
232/232 [==============================] - 0s 1ms/step - loss: 0.4582
Epoch 5/100
232/232 [==============================] - 0s 1ms/step - loss: 0.4295
Epoch 6/100
232/232 [==============================] - 0s 1ms/step - loss: 0.4035
Epoch 7/100
232/232 [==============================] - 0s 1ms/step - loss: 0.3834
Epoch 8/100
232/232 [==============================] - 0s 1ms/step - loss: 0.3655
Epoch 9/100
232/232 [==============================] - 0s 1ms/step - loss: 0.3516
Epoch 10/100
232/232 [==============================] - 0s 1ms/step - loss: 0.3363
Epoch 11/100
232/232 [==============================] - 0s 1ms/step - loss: 0.3242
Epoch 12/100
232/232 [==============================] - 0s 1ms/step - loss: 0.3156
Epoch 13/100
232/232 [==============================] - 0s 1ms/step - loss: 0.3055
Epoch 14/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2942
Epoch 15/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2917
Epoch 16/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2796
Epoch 17/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2761
Epoch 18/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2689
Epoch 19/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2625
Epoch 20/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2547
Epoch 21/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2537
Epoch 22/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2473
Epoch 23/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2429
Epoch 24/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2390
Epoch 25/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2348
Epoch 26/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2316
Epoch 27/100
232/232 [==============================] - 0s 956us/step - loss: 0.2279
Epoch 28/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2242
Epoch 29/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2220
Epoch 30/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2190
Epoch 31/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2176
Epoch 32/100
232/232 [==============================] - 0s 978us/step - loss: 0.2140
Epoch 33/100
232/232 [==============================] - 0s 956us/step - loss: 0.2125
Epoch 34/100
232/232 [==============================] - 0s 946us/step - loss: 0.2143 0s - loss: 0.21
Epoch 35/100
232/232 [==============================] - 0s 956us/step - loss: 0.2116
Epoch 36/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2103
Epoch 37/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2065
Epoch 38/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2065
Epoch 39/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2048
Epoch 40/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2037
Epoch 41/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2054
Epoch 42/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2033
Epoch 43/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2051
Epoch 44/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2021
Epoch 45/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1996
Epoch 46/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1982
Epoch 47/100
232/232 [==============================] - 0s 1ms/step - loss: 0.2014
Epoch 48/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1982
Epoch 49/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1985
Epoch 50/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1946
Epoch 51/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1982
Epoch 52/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1961
Epoch 53/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1950
Epoch 54/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1956
Epoch 55/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1948
Epoch 56/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1961
Epoch 57/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1951
Epoch 58/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1924
Epoch 59/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1912
Epoch 60/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1931
Epoch 61/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1924
Epoch 62/100
232/232 [==============================] - 0s 2ms/step - loss: 0.1929A: 0s - loss:
Epoch 63/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1915
Epoch 64/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1922
Epoch 65/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1905
Epoch 66/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1924
Epoch 67/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1920
Epoch 68/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1916
Epoch 69/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1927
Epoch 70/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1898
Epoch 71/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1893
Epoch 72/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1908
Epoch 73/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1916
Epoch 74/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1892
Epoch 75/100
232/232 [==============================] - 0s 986us/step - loss: 0.1908
Epoch 76/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1873
Epoch 77/100
232/232 [==============================] - 0s 2ms/step - loss: 0.1880
Epoch 78/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1908
Epoch 79/100
232/232 [==============================] - 0s 2ms/step - loss: 0.1879
Epoch 80/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1888
Epoch 81/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1899
Epoch 82/100
232/232 [==============================] - 0s 999us/step - loss: 0.1879
Epoch 83/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1885
Epoch 84/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1870
Epoch 85/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1897
Epoch 86/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1875
Epoch 87/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1890
Epoch 88/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1866
Epoch 89/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1879
Epoch 90/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1866
Epoch 91/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1869
Epoch 92/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1879
Epoch 93/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1863
Epoch 94/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1847
Epoch 95/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1864
Epoch 96/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1870
Epoch 97/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1858
Epoch 98/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1874
Epoch 99/100
232/232 [==============================] - 0s 982us/step - loss: 0.1871
Epoch 100/100
232/232 [==============================] - 0s 1ms/step - loss: 0.1869
<keras.callbacks.History at 0x1d721958c18>
# 保存模型
model.save_weights('temp/net.model')
# 预测
model.predict(X_train) # 预测结果为True的概率,连续值,用于回归
predict_result = model.predict_classes(X_test).reshape(len(X_test)) # 预测类别,离散值,用于分类
predict_result
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0])
绘制混淆矩阵
混淆矩阵每一行之和表示该类别的真实样本数量,每一列之和表示被预测为该类别的样本数量
y_test.shape
(59,)
# 行,真实数据情况
196 + 9 # 205:真实情况的未窃电个数
4 + 23 # 27:真实的窃电个数
205 + 27 # 232,总数据个数
# 列,预测数据情况
196 + 4 # 200 预测的未窃电个数
9 + 23 # 32 预测的窃电个数
200 + 32 # 232,总数
# 混淆矩阵:
196 # 没窃电,且预测未窃电的个数
23 # 窃电,且预测窃电的个数
196 + 23 # 232条数据预测正确219条
9 # 没窃电,但预测未窃电的个数,预测错误
4 # 窃电,但预测为未窃电个数,预测错误
9 + 4 # 132条数据预测错误13条
# 准确率
219 / 232 # 94.4% 精度
# 混淆矩阵的作用:真实场景中 ,预测错误的情况重要性可能相差很多
# 窃电没预测出来,没关系
# 没窃电,冤枉为窃电,误报的后果很严重
0.9439655172413793
from cm_plot import *
cm_plot(y_test, predict_result).show()

CART决策树
from sklearn.tree import DecisionTreeClassifier
tree = DecisionTreeClassifier()
tree.fit(X_train, y_train)
predict_result2 = tree.predict(X_test)
predict_result2
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int64)
#保存模型
import joblib
joblib.dump(tree, 'temp/tree.pkl')
['temp/tree.pkl']
cm_plot(y_test, predict_result2).show()

模型评价
ROC曲线:受试者工作特征曲线
主要用于不能用精度确切衡量模型性能情况(癌症识别模型,100个人里1个得病,预测模型全部预测未得病,准确率99%,没意义)
TP、True Positive 真阳性:预测为正,实际也为正
FP、False Positive 假阳性:预测为正,实际为负
FN、False Negative 假阴性:预测与负、实际为正
TN、True Negative 真阴性:预测为负、实际也为负
- 该曲线的横坐标为假阳性率(False Positive Rate, FPR),
- 纵坐标为真阳性率(True Positive Rate, TPR),
预测和实际一致则为真,预测和实际不一致则为假;如果预测出来是“正”的,则为“阳”,预测结果为 “负”,则为“阴”
ROC曲线:越靠近坐标轴左上角,模型性能越好(越精确)
- 如果完全达到左上角,意味着假阳性为0,真阳性为1
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = ['Arial Unicode MS', 'Microsoft Yahei', 'SimHei', 'sans-serif'] # 全局设置支持中文字体,默认 sans-serif
from sklearn.metrics import roc_curve
predict_result
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0])
predict_result2
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int64)
# 神经网络模型预测结果的ROC曲线
fpr, tpr, threshoulds = roc_curve(y_test, predict_result, pos_label=1)
plt.plot(fpr, tpr, linewidth=2, color='red', alpha=0.5, label='Roc of LM') # 神经网络ROC曲线
fpr, tpr, threshoulds = roc_curve(y_test, predict_result2, pos_label=1)
plt.plot(fpr, tpr, linewidth=2, color='green', alpha=0.5, label='Roc of tree') # 决策树ROC曲线
plt.xlabel('假阳性率:FPR')
plt.ylabel('真阳性率:TPR')
plt.xlim(0, 1.05)
plt.ylim(0, 1.05)
plt.legend()
<matplotlib.legend.Legend at 0x1d7231917f0>

进行窃电诊断
在线监测用户用电负荷及终端报警数据,预处理后得到模型输入数据,
利用构建好的窃电用户识别模型计算用户的窃电诊断结果,实现且漏电用户实时诊断,并与实际稽查结果作对比
可以发现:
正确识别出异常用户10个,错误判断用户为异常用户的1个,没发现的异常用户4个,整体看诊断准确率是比较高的,
下一步工作是针对漏判用户,研究其在且漏电期间的用电行为,优化模型特征,提高识别准确率