传统的防窃漏电方法对人的依赖性太强,且采用这种方法建模时,模型各输入指标权重的确定需要用专家的知识和经验来判断,具有很大主观性。
现有的电力计量自动化系统能够采集到各相电流、电压、功率因数等用电负荷数据以及用电异常等终端报警信息。异常告警信息和用电负荷数据能够反映用户的用电情况,同时稽查工作人员也会通过在线稽查系统和现场稽查来找出窃漏电用户,并录入系统。若能通过这些数据信息提取出窃漏电用户的关键特征,构建窃漏电用户的识别模型,就能自动检查、判断用户是否存在窃漏电行为。
数据挖掘建模目标:
1)归纳出窃漏电用户的关键特征,构建窃漏电用户的识别模型;
2)利用实时监测数据,调用窃漏电用户识别模型实现实时诊断。
主要包括以下步骤:
1)从电力计量自动化系统、营销系统有选择性地抽取部分大用户用电负荷、终端报警及违约窃电处罚信息等原始数据。
2)对样本数据探索分析,剔除不可能存在窃漏电行为行业的用户,即白名单用户,初步审视正常用户和窃漏电用户的用电特征。
3)对样本数据进行预处理,包括数据清洗、缺失值处理和数据变换。
4)构建专家样本集。
5)构建窃漏电用户识别模型。
6)在线监测用户用电负荷及终端报警,调用模型实现实时诊断。
相关数据有:
(1)从营销系统抽取的数据
1)用户基本信息:用户名称、用户编号、用电地址、用电类别、报装容量、计量方式、电流互感器变比、电压互感器变比。
2)违约、窃电处理记录。
3)记量方法及依据。
(2)从计量自动化系统采集的数据属性
1)实时负荷:时间点、计量点、总有功功率、A/B/C相有功功率、A/B/C相电流、A/B/C相电压、A/B/C相功率因数。
2)终端报警。
建模样本要包含不同用电类别的所有窃漏电用户及部分正常用户。在窃漏电用户的窃漏电开始时间和结束时间点上,用电负荷和终端报警等数据会有一定的特征变化,故样本数据要包含关键时间点前后一定范围的数据,并通过负荷数据计算当天的用电量。
f l = 0.25 ∑ m i ∈ l 天 m i f_{l}=0.25\sum_{m_{i}∈l天}m_{i} fl=0.25mi∈l天∑mi
其中fl为第l天的用电量,mi为第l天每隔15分钟的总有功功率,对其累加求和得到当天用电量。
数据探索分析是对数据进行初步研究,发现数据的内在规律特征,有助于选择合适的数据预处理和数据分析技术。
本案例主要采用分布分析和周期性分析等方法对电量数据进行数据探索分析。
1.分布分析
对各个用电类别的窃漏电用户的分布情况进行统计,从中发现非居民类别不存在窃漏电情况,故在接下来的分析中不考虑非居民类别的用电数据。
书没有对前期的数据探索提供数据,因此这里只能根据书的结果来
2.周期性分析
随机抽取一个正常用户和一个窃漏电用户,对其采用周期性分析。
(1)正常用电电量探索分析
总体用量较为平稳,没有太大的波动
(2)窃漏电用户电量探索分析
该用户用电量出现明显下降的趋势。
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_excel('./demo/data/正常用电电量数据.xlsx')
# print(data)
plt.figure('正常用电用户电量趋势',figsize=(6, 4))
plt.plot(data['日期'], data['日电量(kW)'])
plt.xlabel('日期')
x_major_locator = plt.MultipleLocator(3) # x轴主刻度间隔为3
ax = plt.gca()
ax.xaxis.set_major_locator(x_major_locator)
ax.xaxis.set_minor_locator(plt.MultipleLocator(1)) # x轴副刻度间隔为1
plt.xticks(rotation=40) # 将x轴文本倾斜40°
plt.ylabel('日电量(kW)')
plt.title('正常用电用户电量趋势')
data2 = pd.read_excel('./demo/data/窃漏电用户电量数据.xlsx')
# print(data)
plt.figure('窃漏电用户电量趋势',figsize=(6, 4))
plt.plot(data2['日期'], data2['日电量(kW)'])
plt.xlabel('日期')
x_major_locator = plt.MultipleLocator(3)
ax = plt.gca()
ax.xaxis.set_major_locator(x_major_locator)
ax.xaxis.set_minor_locator(plt.MultipleLocator(1))
plt.xticks(rotation=40)
plt.ylabel('日电量(kW)')
plt.title('窃漏电用户电量趋势')
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用于正常显示中文标签
plt.tight_layout()
plt.show() # 展示图片
分析结论:正常用电到窃漏电过程是用电量持续下降的过程,该用户从2014年9月1日开始用电量下降,并且持续下降,这就是用户开始窃漏电时所表现出来的重要特征。
1.数据清洗
数据清洗的主要目的是从业务以及建模的相关需要方面考虑,筛选出需要的数据。案例主要进行如下操作:
1)通过数据的探索分析,发现在用电类别中,非居民用电类别不可能存在漏电窃电现象,需要将非居民用电类别的用电数据过滤掉。
2)结合本案例的业务,节假日用电量与工作日相比,会明显偏低,因此过滤节假日的用电数据。
2.缺失值处理
在原始计量数据,特别是用户电量抽取过程中,发现存在缺失的现象。若直接抛弃缺失值则会影响计算结果,因此采用拉格朗日插值法对缺失值进行插补。
首先从原始数据集中确定因变量和自变量,取出缺失值前后5个数据(前后数据中遇到数据不存在或者为空的,直接将数据舍去,将仅有的数据组成一组),根据取出来的10个数据组成一组,然后采用拉格朗日多项式插值公式。
import pandas as pd
from scipy.interpolate import lagrange
inputfile = './demo/data/missing_data.xls'
outputfile = './demo/tmp/missing_data_processed.xlsx'
data = pd.read_excel(inputfile, header=None)
# 自定义列向量插值函数
# s为列向量,n为被插值的位置,k为取前后的数据个数,默认为5
def ployinterp_column(s, n, k=5):
if n>=k and n<=len(s)-k-1:
y = s[list(range(n-k, n))+list(range(n+1, n+k+1))] # 取缺失值前后5个数据
y = y[y.notnull()] # 剔除空值
elif n<k:
y = s[list(range(0, n)) + list(range(n + 1, n + k + 1))] # 取缺失值前面所有数据和后面5个数据
y = y[y.notnull()] # 剔除空值
else:
y = s[list(range(n-k, n)) + list(range(n + 1, len(s)))] # 取缺失值前面所有数据和后面5个数据
y = y[y.notnull()] # 剔除空值
return lagrange(y.index, list(y))(n)
# 逐个元素判断是否需要插值
for i in data.columns:
for j in range(len(data)):
is_null = data[i].isnull()
if is_null[j]: # 如果为空则插值
data.iloc[j, i] = ployinterp_column(data[i], j)
data.to_excel(outputfile, header=None, index=False) # 输出结果
由于第六个数据之前的数据前面不足5个数据,因此需要修改代码为拿取前面所有数据;而第15个数据之后的数据不足5个数据,因此需要修改代码为拿取后面所有数据。
3.数据变换
为构建模型的专家样本,需要对数据进行重新构造。
基于数据变换,得到新的评价指标来表征窃漏电行为所具有的规律,评价指标体系如图所示:
(1)电量趋势下降指标
由窃漏电用户的用电量呈现下降的趋势,然后趋于平缓,因此可考虑前后几天作为统计窗口期,考虑期间的下降趋势,利用电量做直线拟合得到的斜率作为衡量,如果斜率随时间不断下降,那该用户的窃漏电可能性很大。
对统计当天设定前后5天为统计窗口期,计算这11天内的电量趋势下降情况。
第i天的用电量趋势是考虑前后5天期间的用电量斜率,即
k i = ∑ l = i − 5 i + 5 ( f l − f ˉ ) ( l − l ˉ ) ∑ l = i − 5 i + 5 ( l − l ˉ ) 2 k_{i}=\frac{\sum_{l=i-5}^{i+5}(f_{l}-\bar{f})(l-\bar{l})}{\sum_{l=i-5}^{i+5}(l-\bar{l})^{2}} ki=∑l=i−5i+5(l−lˉ)2∑l=i−5i+5(fl−fˉ)(l−lˉ)
其中, f ˉ = 1 11 ∑ l = i − 5 i + 5 f l , l ˉ = 1 11 ∑ l = i − 5 i + 5 l \bar{f}=\frac{1}{11}\sum_{l=i-5}^{i+5}f_{l},\bar{l}=\frac{1}{11}\sum_{l=i-5}^{i+5}l fˉ=111∑l=i−5i+5fl,lˉ=111∑l=i−5i+5l,ki为第i天的电量趋势,fl为第l天的用电量。
若电量趋势为不断下降的,则认为具有一定的窃电嫌疑,故计算这11天内,当天比前一天用电量趋势为递减的天数,即设有
D ( i ) = { 1 k i < k i − 1 0 k i ≥ k i − 1 D(i)= \begin{cases}1 & k_{i} < k_{i-1} \\ 0 & k_{i} \ge k_{i-1} \end{cases} D(i)={10ki<ki−1ki≥ki−1
则这11天内的电量趋势下降指标为
T = ∑ n = i − 4 i + 5 D ( n ) T=\sum_{n=i-4}^{i+5}D(n) T=n=i−4∑i+5D(n)
(2)线损指标
线损率是用于衡量供电线路的损失比例,一条线路上同时供给多个用户,若第l天的线路供电量为sl,线路上各个用户的总用电量为 ∑ m f l ( m ) \sum_{m}f_{l}^{(m)} ∑mfl(m),线路的线损率公式为:
t l = s l − ∑ m f l m s l ∗ 100 % t_{l}=\frac{s_{l}-\sum_{m}f_{l}^{m}}{s_{l}}*100\% tl=slsl−∑mflm∗100%
线路的线损率可作为用户线损率的参考值,若用户发生窃漏电,则当天的线损率会上升,因此对统计当天设定前后5天为统计窗口期,首先分别统计当天与前5天之间的线损率平均值Vi1和后5天之间的线损率平均值Vi2,若Vi1比Vi2的增长率大于1%。则认为具有一定的窃电嫌疑,故定义线损指标
E ( i ) = { 1 V i 1 − V i 2 V i 2 > 1 % 0 V i 1 − V i 2 V i 2 ≤ 1 % E(i)= \begin{cases}1 & \frac{V_{i}^{1}-V_{i}^{2}}{V_{i}^{2}} >1\% \\ 0 & \frac{V_{i}^{1}-V_{i}^{2}}{V_{i}^{2}} \le 1\% \end{cases} E(i)=⎩⎨⎧10Vi2Vi1−Vi2>1%Vi2Vi1−Vi2≤1%
(3)告警类指标
与窃漏电相关的终端报警主要有电压缺相、电压断相、电流反极性等警告,计算发生与窃漏电相关的终端报警的次数总和,作为告警类指标。
按照以上指标对数据进行处理,得到专家样本库。
1.构建窃漏电用户识别模型
将专家样本划分成测试样本和训练样本,随机抽取20%作为测试样本,剩下的作为训练样本。构建LM神经网络和CART决策树模型,输入项包括电量趋势下降指标、线损类指标和告警类指标,输出项为窃漏电标识。
(1)数据划分
对专家样本随机选取20%作为测试样本,剩下的80%作为训练样本。
(2)LM神经网络
这里TensorFlow只支持较低版本的python,我的是3.10版本的,出于麻烦选择不做神经网络模型,做决策树模型
(3)CART决策树
# 将原始数据分为训练数据和测试数据
import pandas as pd
from random import shuffle # 导入随机函数shuffle,用来打散数据
data = pd.read_excel('./demo/data/model.xls') # 读取数据,前三列是特征,第四列是标签
data = data.values # 将表格转成数组
# print(data)
shuffle(data) # 随机打乱数据
p = 0.8 # 设置训练集比例
train = data[:int(len(data)*p), :] # 前80%为训练集
test = data[int(len(data)*p):, :] # 后20%为测试集
# print(train)
# print('\n',test)
from sklearn.tree import DecisionTreeClassifier # 导入决策树模型
treefile = './demo/tmp/tree.pkl' # 模型输出名字
tree = DecisionTreeClassifier() # 建立决策树模型
tree.fit(train[:, :3], train[:, 3])
# 保存模型
import joblib # joblib已经从sklearn.externals库里独立出来,直接导入即可
joblib.dump(tree, treefile)
from cm_plot import * # 导入自行编写的混淆矩阵可视化函数
cm_plot(train[:, 3], tree.predict(train[:, :3])).show() # 显示混淆矩阵可视化结果
# Scikit-Learn 使用predict方法直接给出预测结果
2.模型评价
对决策树模型的分类准确率为(166+60)/(166+3+3+60)=97.4%,正常用户被误判为窃漏电用户占用户的3/(3+166)=1.8%,窃漏电用户被误判为正常用户占正常窃漏电用户的3/(3+60)=4.8%。为了进一步评估模型分类的性能,利用测试样本对模型进行评价,采用ROC曲线评价方法进行评估,一个优秀分类器所对应的ROC曲线应该是靠近左上角的。
from sklearn.metrics import roc_curve # 导入ROC曲线函数
fpr, tpr, thresholds = roc_curve(test[:, 3], tree.predict_proba(test[:, :3])[:, 1], pos_label=1)
plt.plot(fpr, tpr, linewidth=2, label='ROC of CART') # 作出ROC曲线
plt.xlabel('False Positive Rate') # 坐标轴标签
plt.ylabel('True Positive Rate') # 坐标轴标签
plt.ylim(0, 1.05) # 边界范围
plt.xlim(0, 1.05) # 边界范围
plt.legend(loc=4) # 图例
plt.show()
3.进行窃漏电诊断
在线监测用户用电负荷及终端报警数据,经过数据预处理,得到模型输入数据,利用构建好的窃漏电用户用电识别模型计算用户的窃漏电诊断结果,实现窃漏电用户实时诊断并与实际稽查结果作对比。再针对漏判的用户研究其在窃漏电期间的用电行为,优化模型的特征,提高识别的准确率。