数据挖掘实战(1)—— 电力窃漏电用户识别

欢迎关注天善智能,我们是专注于商业智能BI,人工智能AI,大数据分析与挖掘领域的垂直社区,学习,问答、求职一站式搞定!

对商业智能BI、大数据分析挖掘、机器学习,python,R等数据领域感兴趣的同学加微信:tstoutiao,邀请你进入数据爱好者交流群,数据爱好者们都在这儿。

作者: wltongxue

博客:https://wltongxue.github.io/


本次学习我们将使用

“什么是数据挖掘”

中的挖掘过程:根据实际问题定义挖掘目标、取什么样的原始数据、对原始数据的探索分析、如何对数据进行处理、建立合适的模型完成目标、评估模型完成的好不好。

问题背景:实际生活中,有很多人可能会偷别人的电用,或者计量电量的设备坏了,造成无法根据实际用电情况计价,可能导致用户多交或少交了钱。我们可以使用自动化设备实现对用户用电负荷等数据进行采集,通过从这个数据中找到异常的情况。

一、挖掘目标

1、归纳出窃漏电用户的关键特征,构建窃漏电用户的识别模型
2、利用实时监测数据,调用窃漏电用户识别模型实现实时判断是否是窃漏电用户。
根据目标可以知道这类问题属于分类预测问题,根据数据预测这个用户属于哪一类用户,到底是正常用户,还是偷电用户?所以我们后面会考虑用分类和预测的算法模型进行建模。

二、数据抽取:

1、从营销系统抽取用户信息
2、从计量自动化系统采集电量、负荷等
如下图,你可以看到能实际采集到的数据如下

数据挖掘实战(1)—— 电力窃漏电用户识别_第1张图片

三、数据探索:分布分析+周期性分析

探索与预测无关的数据,缩小数据集范围,达到精准预测

1、分布分析

统计5年内所有窃漏用户进行分布分析,统计出各个用电类别的窃漏电用户分布情况,如下图所示,可以发现非居民类别不存在窃漏电情况,故在接下来的分析中不考虑非居民类别的用电数据

数据挖掘实战(1)—— 电力窃漏电用户识别_第2张图片

2、周期性分析

随机抽取一个正常用电用户和一个窃漏电用户,周期性对电量进行探索。
(1)正常用电,如下图所示,总体来说用电量比较平稳,没有太大的波动。

数据挖掘实战(1)—— 电力窃漏电用户识别_第3张图片
数据挖掘实战(1)—— 电力窃漏电用户识别_第4张图片

分析结论:窃漏电的过程就是用电量持续下降的过程。

四、数据预处理

数据本身的样子可能并不适合我们处理,比如跟预测结论没有关系的数据,我们可以过滤掉。比如存在一些缺失值,样本很多的情况下我们就大方的删了,但样本很少的时候,我们就需要把它补上。比如好多个数据之间有明显的关系,我们可以把他们合并为一个数据作为特征明显指标。总之,我们对于数据的预处理目的就是:用尽可能少的数据探索出尽可能精准的结果。
1、缺失值可以删除也可以插补,插补的方法很多,我们这里使用“拉格朗日插值法”进行数据的补充,(该数学推导请看这里):https://wltongxue.github.io/%E6%8B%89%E6%A0%BC%E6%9C%97%E6%97%A5%E6%8F%92%E5%80%BC%E6%B3%95/

我们这里调用python库中已经实现的拉格朗日函数对样本数据进行插值,代码如下:

 
   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

 
   

#-*-coding:utf-8 -*-
#拉格朗日插值代码
import pandas as pd #导入数据分析库
from scipy.interpolate import lagrange #导入拉格朗日函数

inputfile = '../data/missing_data.xls'#输入数据路径,需要使用ecel格式
outputfile= '../tmp/missing_data_processed.xls' #输出数据路径,需要使用Excel格式

data=pd.read_excel(inputfile,header=None) #读入数据

#自定义列向量插值函数
#s为列向量(表中某个字段的所有数据),n为被插值的位置,k为取前后的数据个数,默认为5
#取总共11个数据构建拉格朗日函数
def ployinterp_column(s,n,k=5):
y=s[list(range(n-k,n)) + list(range(n+1,n+1+k))]
y=y[y.notnull()]#剔除空值
return lagrange(y.index,list(y))(n) #插值并返回插值结果

#逐个元素判断是否需要插值
for i in data.columns:
for j in range(len(data)):
if(data[i].isnull())[j]:#如果为空即插值
data[i][j]=ployinterp_column(data[i],j)

#输出结果
data.to_excel(outputfile,header=None,index=False)

如下图,拉格朗日插补法的效果如下:

数据挖掘实战(1)—— 电力窃漏电用户识别_第5张图片
数据挖掘实战(1)—— 电力窃漏电用户识别_第6张图片

五、模型构建

我们已经完成的数据的处理,现在的数据可以用来训练和测试模型。
重点来了,由于我们是分类问题,所以我们从分类模型中选择模型。这里实际上是一个二分类问题,结果只有0或者1,此时我们就不会选择回归分析(因为回归分析是分析连续性结果);并且我们的属性并不多,所以我们会更倾向选择决策树算法或者神经网络算法。这里在决策树算法中选择CART算法(算法详解请看这里“https://wltongxue.github.io/CART/”),在神经网络算法中选择LM算法(算法详解请看这里:https://wltongxue.github.io/LM-BP/)。实际上其他一些算法也能应用于该问题,感兴趣的读者也可以尝试效果,我们在这里只选择两个常见的进行比较。
我们的整体过程如下图,

数据挖掘实战(1)—— 电力窃漏电用户识别_第7张图片

这里稍微简单的说一下机器学习的过程,首先切分数据集为训练集和测试集(也可以是独立的两个数据集),然后我们选择合适的算法,每种算法模型都可以有多种参数,但是确定什么样的参数才能解决我们当前的问题,这就需要训练集一个一个的带入到算法模型里然后一步一步的调整到合适的参数获得模型。最后我们需要把测试集代入到训练好的模型里,评估一下这个模型是不是在任何该问题的数据下都能够准确的得到预测结果。评估分类模型的指标也有很多(参考

数据挖掘实战讲解系列(1)——什么是数据挖掘

),本章我们选择ROC曲线(什么是ROC曲线:https://wltongxue.github.io/ROC/)。

按照上图的步骤我们进行代码的编写:

1、数据划分代码:
导入291个样本,将数据分为训练集和测试集

 
   

1
2
3
4
5
6
7
8
9
10
11

 
   

import pandas as pd #导入数据分析库
from random import shuffle #导入随机函数shuffle,用来打乱数据

datafile='../data/model.xls' #数据名
data=pd.read_excel(datafile) #读取数据,数据的前三列是特征,第四列是标签
data=data.as_matrix() #将表格转换为矩阵
shuffle(data) #随机打乱数据

p = 0.8 #设置训练数据比例
train=data[:int(len(data)*p),:]#前80%为训练集
test=data[int(len(data)*p):,:]#后20%为测试集

2、LM神经网络算法:
这里用到了python的神经网络库keras,构建三层网络模型,训练模型并且保存模型。这里的ROC曲线代码在评估阶段提供

 
   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

 
   

#########构建LM神经网络模型##########
from keras.models import Sequential #导入神经网络初始化函数
from keras.layers.core import Dense,Activation #导入神经网络层函数、激活函数
from keras.models import load_model

netfile='../tmp/net.model' #构建的神经网络模型存储路径

net = Sequential() #简历神经网络
net.add(Dense(input_dim=3,output_dim=10)) #添加输入层(3节点)到隐藏层(10节点)的连接
net.add(Activation('relu')) #隐藏层使用relu激活函数
net.add(Dense(input_dim=10,output_dim=1)) #添加隐藏层(10节点)到输出层(1节点)的连接
net.add(Activation("sigmoid"))#输出层使用sigmoid激活函数
#导入训练好的model_weights
#net.load_weights(netfile)
#编译模型,使用adam方法求解
net.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])

#:3标识前3列(因为第四列是标签)
net.fit(train[:,:3],train[:,3],nb_epoch=1000,batch_size=1)#训练模型,循环1000次
net.save_weights(netfile) #保存模型
predict_result = net.predict_classes(train[:,:3]).reshape(len(train))#预测结果变形
'''这里要提醒的是,keras用predict给出预测概率,predict_class才是给出预测类别,
   而且两者的预测结果都是n x 1维数组,而不是通常的1 下n'''

from cm_plot import * #导入自行编写的混淆矩阵可视化函数()
cm_plot(train[:,3],predict_result).show() #显示混淆矩阵可视化结果
#显示ROC曲线
predict_result_test=net.predict(test[:,:3]).reshape(len(test)) #预测结果变形
roc_plot(test[:,3],predict_result_test ,'ROC of LM')

3、CART决策树
这里使用python的sklearn库

 
   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

 
   

#构建CART决策树模型
from sklearn.tree import DecisionTreeClassifier #导入决策树模型

treefile='../tmp/tree.pk1'#模型输出名字
tree = DecisionTreeClassifier() #建立决策树模型
tree.fit(train[:,:3],train[:,3]) #训练

#保存模型
from sklearn.externals import joblib
joblib.dump(tree,treefile)

from cm_plot import * #导入画混淆矩阵和ROC曲线的模块(自定义模块)
cm_plot(train[:,3],tree.predict(train[:,:3])).show() #显示混淆矩阵
#注意到Scikit-Learn使用predict方法直接给出预测结果
#显示roc曲线
roc_plot(test[:,3],tree.predict_proba(test[:,:3])[:,1],'ROC of CART')

4、ROC曲线

 
   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

 
   

import matplotlib.pyplot as plt #包含画图工具

'''画混淆矩阵图'''
def cm_plot(y, yp):
 
 from sklearn.metrics import confusion_matrix #导入混淆矩阵函数
 cm = confusion_matrix(y, yp) #混淆矩阵

 plt.matshow(cm, cmap=plt.cm.Greens) #画混淆矩阵图,配色风格使用cm.Greens,更多风格请参考官网。
 plt.colorbar() #颜色标签
 
 for x in range(len(cm)): #数据标签
   for y in range(len(cm)):
     plt.annotate(cm[x,y], xy=(x, y), horizontalalignment='center', verticalalignment='center')
 
 plt.ylabel('True label') #坐标轴标签
 plt.xlabel('Predicted label') #坐标轴标签
 return plt

'''画ROC曲线图'''
#绘制决策树模型的ROC曲线
from sklearn.metrics import roc_curve #导入ROC曲线函数
def roc_plot(x,xp,l):
   fpr,tpr,thresholds=roc_curve(x,xp,
                            pos_label=1)
   plt.plot(fpr,tpr,linewidth=2,label=l) #做出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() #显示作图结果
   return plt

在这里补充一下,每一次随机分的训练集和测试集并不完全相同,代码运行一次,分一次数据集,就不一样一次,所以每一次的训练得出的模型并不是完全相同的,但我们希望比较两个算法的优缺点时,我们希望他们要用同一个训练集,同一个测试集,所以这里补充一下,把两个算法写在一起训练并且比较ROC曲线更有说服力。(ps:上面的训练集划分和两个算法的代码可以等同于如下:)

 
   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

 
   

#coding=utf-8
import sys
reload(sys)
sys.setdefaultencoding('ISO-8859-1')

'''读取数据,设置数据'''
import pandas as pd #导入数据分析库
from random import shuffle #导入随机函数shuffle,用来打乱数据

datafile='../data/model.xls' #数据名
data=pd.read_excel(datafile) #读取数据,数据的前三列是特征,第四列是标签
data=data.as_matrix() #将表格转换为矩阵
shuffle(data) #随机打乱数据

p = 0.8 #设置训练数据比例
train=data[:int(len(data)*p),:]#前80%为训练集
test=data[int(len(data)*p):,:]#后20%为测试集

#让LM和CART使用同一个数据分法进行比较

'''LM预测'''
#########构建LM神经网络模型##########
from keras.models import Sequential #导入神经网络初始化函数
from keras.layers.core import Dense,Activation #导入神经网络层函数、激活函数
from keras.models import load_model

netfile='../tmp/net.model' #构建的神经网络模型存储路径

net = Sequential() #简历神经网络
net.add(Dense(input_dim=3,output_dim=10)) #添加输入层(3节点)到隐藏层(10节点)的连接
net.add(Activation('relu')) #隐藏层使用relu激活函数
net.add(Dense(input_dim=10,output_dim=1)) #添加隐藏层(10节点)到输出层(1节点)的连接
net.add(Activation("sigmoid"))#输出层使用sigmoid激活函数
#编译模型,使用adam方法求解
net.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])

#:3标识前3列(因为第四列是标签)
net.fit(train[:,:3],train[:,3],nb_epoch=1000,batch_size=1)#训练模型,循环1000次
net.save_weights(netfile) #保存模型

predict_result = net.predict_classes(train[:,:3]).reshape(len(train))#预测结果变形
'''这里要提醒的是,keras用predict给出预测概率,predict_class才是给出预测类别,
   而且两者的预测结果都是n x 1维数组,而不是通常的1 下n'''

'''CART预测'''
#构建CART决策树模型
from sklearn.tree import DecisionTreeClassifier #导入决策树模型
tree = DecisionTreeClassifier() #建立决策树模型
tree.fit(train[:,:3],train[:,3]) #训练


'''画混淆矩阵和ROC曲线'''
from cm_plot import * #导入自行编写的混淆矩阵可视化函数()
cm_plot(train[:,3],predict_result).show() #显示混淆矩阵可视化结果
cm_plot(train[:,3],tree.predict(train[:,:3])).show() #显示混淆矩阵
#显示ROC曲线
predict_result_test=net.predict(test[:,:3]).reshape(len(test)) #预测结果变形
roc_plot(test[:,3],predict_result_test ,'ROC of LM')
roc_plot(test[:,3],tree.predict_proba(test[:,:3])[:,1],'ROC of CART')

六、模型评价

根据上述两个算法同时比较的代码,可得到如下ROC曲线。

数据挖掘实战(1)—— 电力窃漏电用户识别_第8张图片

Python的爱好者社区历史文章大合集

2018年Python爱好者社区历史文章合集(作者篇)

2018年Python爱好者社区历史文章合集(类型篇)

3901436-a73dd124e585ab45

关注后在公众号内回复“ 课程 ”即可获取:

小编的转行入职数据科学(数据分析挖掘/机器学习方向)【最新免费】

小编的Python的入门免费视频课程

小编的Python的快速上手matplotlib可视化库!

崔老师爬虫实战案例免费学习视频。

陈老师数据分析报告扩展制作免费学习视频。

玩转大数据分析!Spark2.X + Python精华实战课程免费学习视频。

数据挖掘实战(1)—— 电力窃漏电用户识别_第9张图片

你可能感兴趣的:(数据挖掘实战(1)—— 电力窃漏电用户识别)