本文完整的敘述了數據分析實戰項目“電力竊漏電用戶自動識別”,包括數據探索分析、數據預處理、專家樣本的構建、模型的構建以及模型的評價等。
1.背景方面
傳統的防竊漏電方法主要通過定期巡檢、定期校驗電錶、用戶舉報竊電等方法來發現竊電或計量裝置故障。但這種方法對人的依賴性太強,抓竊查漏的目標不明確。通過採集電量異常、負荷異常、終端報警、主站報警、線損異常等信息,建立數據分析模型,來實時監測竊漏電情況和發現計量裝置的故障。
本次數據挖掘與數據分析目標:
(1)歸納出竊漏電用戶的關鍵特徵,構建竊漏電用戶的識別模型;
(2)利用實時監測數據,調用竊漏電用戶識別模型實現實時診斷;
2.分析過程
竊漏電用戶在電力計量自動化系統的監控大用戶中只佔一小部分,同時某些大用戶也不可能存在竊漏電行爲,如銀行、稅務、學校和工商等非居民類別,故在數據預處理時候有必要將這些類別用戶剔除。
系統中的用電負荷不能直接體現出用戶的竊漏電行爲,終端報警存在很多誤報和漏報的情況,故需要進行數據探索和預處理,總結竊漏電用戶的行爲規律,再從數據中提煉出描述竊漏電用戶的特徵指標。
最後結合歷史竊漏電用戶信息,整理出識別模型的專家樣本數據集,再進一步構建分類模型,實現竊漏電用戶的自動識別。
竊漏電用戶識別流程如下圖所示,主要包話以下步驟:
(1)從電力計量自動化系統、營銷系統有選擇性地抽取部分大用戶用電負荷、終端報警及違約竊電處罰信息等原始數據。
(2)對樣本數據探索分析,剔除不可能存在竊漏電行爲行業的用戶,即白名單用戶,初步審視正常用戶和竊漏電用戶的用電特徵。
(3)對樣本數據進行預處理,包括數據清洗、缺失值處理和數據變換。
(4)構建專家樣本集。
(5)構建竊漏電用戶識別模型。
(6)在線監測用戶用電負荷及終端報警,調用模型實現實時診斷。
3.數據探索分析
(1)數據分佈分析
對數據所在時間段的所有切點用戶進行分佈分析,統計出各個用電類別的竊漏電用戶分佈情況,如下圖所示。從下面的結果可以看出非居民類別不存在竊漏電情況,故在接下來的分析中不考慮非居民類別的用電數據。
(2)數據週期性分析
如下圖所示分別爲一個正常用電用戶和一個竊漏電用戶的用電量統計結果。可以看出正常用戶用電量比較平穩,沒有太大的波動,這就是用戶正常用電的電量指標特徵。而從竊漏電用戶的統計中就能看出用戶用電量有明顯的下降趨勢,這就是用戶異常用電的電量指標特徵。
綜上所述,正常用電到竊漏電過程是用電量持續下降的過程。
4.數據預處理
針對上述問題的數據預處理包括數據清洗、缺失值處理和數據變換等方面。
4.1 數據清洗
數據清洗主要從業務以及建模相關需要方面考慮,篩選出需要的數據。本案例主要進行一下操作:
(1)通過數據的探索分析,發現在用戶類別中,非居民用電類別不可能存在竊漏電現象,需要將非居民用電類別的用電數據過濾掉;
(2)結合相關業務分析,節假日用電量與工作日相比,會明顯降低。爲了儘可能達到較好的數據效果,過濾掉節假日的用電數據。
4.2 缺失值處理
在原始計量數據,特別是用戶電量抽取過程中,發現存在缺失值。若將這些數據去掉,會嚴重影響供出電量的計算結果,最終導致日線損率數據誤差偏大。爲了達到較好的仿真效果,需要對缺失值處理,本案例採用拉格朗日插值法對缺失值進行插補。具體方法如下:
首先從原始數據中確定因變量和自變量,取出缺失值前後各5個數據(前後數據中遇到數據不存在或者爲空的,直接將其捨去,將僅有的數據組成一組),根據取出來的10個數據組成一組。
拉格朗日公式如下:
其中,x爲缺失值對應的下標序號,Ln(x)爲缺失值的插值結果,xi爲缺失值yi的下標序號。對全部缺失數據進行插值,知道不存在缺失值爲止。代碼如下所示:
#-*- coding:utf-8 -*-
##拉格朗日插值處理數據缺失值
import pandas as pd
from scipy.interpolate import lagrange ##通過SciPy導入插值函數lagrange
"""
給出源文件的路徑和處理後文件的路徑,Excel格式
"""
inputfile = "F:\DeskTop\Python-Data\chapter6\demo\data\missing_data.xls"
outputfile = "F:\DeskTop\Python-Data\chapter6\demo\data\missing_data_processed.xls"
data = pd.read_excel(inputfile,header=None) ##讀入數據
"""
自定義列向量插值函數
s爲列向量,n爲被插值的位置,k爲取前後的數據個數,默認爲5
"""
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) #輸出結果
4.3數據變換
通過電力計量系統採集的電量、負荷,雖然在一定程度上能反映用戶竊漏電行爲的某些規律,但要作爲構建模型的專家樣本,特徵不明顯,需要進行重新構造。基於數據變換,得到新的評價指標來表徵竊漏電行爲所具有的規律,其評價指標體系如圖6巧所示。
(1)電量趨勢下降指標
對統計當天設定前後5天爲統計窗口,計算這11天內的電量趨勢下降情況。首先計算這11天每天的電量趨勢,其中第i天的用電量趨勢是考慮前後5天期間的用電量斜率,即:
若電量趨勢爲不斷下降的,則認爲具有一定的竊點嫌疑,故計算這11天內,當天比前一天用電量趨勢爲遞減的天數,即設有:
則這11天內的電量趨勢下降指標爲:
(2)線損指標
線損率是用於衡量供電線路的損失比例,同時可結合線戶拓撲關係計算出用戶所屬線路在當天的線損率,一條線路上同時供給多個用戶,若第l天的線路供電量爲sl,線路上各個用戶的總用電量可計算出,故線損率公式爲:
如果用戶發生竊電,則當天的線損率會上升,用戶每天用電量存在波動,以天爲單位,誤差較大,所以考慮前後幾天(5天)的線損率的平均值,判斷增長率是否大於1%,若大於1%,則認爲是竊電。前5天的線損率平均值V[i1],後5天的平均值V[i2],若V[i1]比V[i2]的增長率大於1%,認爲有竊電嫌疑。故定義線損率指標:
(3)告警類指標
與竊電相關的終端告警數,計算髮生與漏電相關的報警的總次數。
5.構建專家樣本
最終得到的專家樣本庫如下所示,專家樣本共291個。
6.模型構建
數據劃分:隨機選取20%數據作爲測試樣本,剩下的80%作爲訓練樣本。
模型選擇:竊漏電用戶識別可通過構建分類預測模型來實現,比較常用的分類預測有LM神經網絡和CART決策樹,各個模型都有優缺點,故採用這兩種方法構建竊漏電用戶識別,並從中選擇最優的分類模型。
模型建立後,得到對訓練數據的混淆矩陣,通過計算預測準確率等指標對模型進行初步評價。
爲了進一步評估模型的分類性能,利用之前的20%測試樣本進行預測。採用ROC曲線評價方法,一個優秀的分類器所對應的ROC曲線應該是儘可能靠近左上角的。分別畫出LM神經網絡和CART決策樹在測試樣本下的ROC曲線,對模型進一步評估。
6.1 LM神經網絡模型構建及模型評價
LM神經網絡模型如下:
輸入節點:3
輸出節點:1
隱藏節點:10
優化函數:adam
隱藏層激活函數:relu
輸出層激活函數:sigmoid
LM神經網絡模型構建及模型評價代碼如下所示:
#-*- coding:utf-8 -*-
import pandas as pd
from random import shuffle
from sklearn.metrics import confusion_matrix,roc_curve ##導入混淆矩陣,ROC曲線函數
import matplotlib.pyplot as plt
from keras.models import Sequential ##導入神經網絡初始化函數
from keras.layers.core import Dense,Activation ##導入神經網絡層函數、激活函數
datafile = "F:\DeskTop\Python-Data\chapter6\demo\data\model.xls"
data = pd.read_excel(datafile)
data = data.as_matrix()
shuffle(data)
p = 0.8 #訓練數據佔總數據量的80%
train = data[:int(len(data)*p),:]
test = data[int(len(data)*p):,:]
netfile = "F:\DeskTop\Python-Data\chapter6\demo\data\lm_net.model" #構建的神經網絡模型存儲路徑
net = Sequential() ##建立神經網絡
net.add(Dense(input_dim=3,units = 10)) ##添加輸入層(3節點)到隱藏層(10節點)的連接
net.add(Activation("relu")) ##隱藏層使用relu激活函數
net.add(Dense(input_dim=10,units = 1)) ##添加隱藏層(10節點)到輸出層(1節點)的連接
net.add(Activation("sigmoid")) ##輸出層使用sigmoid激活函數
net.compile(loss="binary_crossentropy",optimizer="adam") #編譯模型,使用adam求解
net.fit(train[:,:3],train[:,3],epochs=1000,batch_size=1) #訓練模型,循環1000次
net.save_weights(netfile)
"""
keras用predict給出預測概率,predict_classes纔是給出預測類別,而且兩者的預測結果
都是n x 1維數組,而不是通常的 1 x n
"""
predict_result = net.predict_classes(train[:,:3]).reshape(len(train)) ##將預測結果變形爲一維數組
cm = confusion_matrix(train[:,3],predict_result) ##得到混淆矩陣
plt.matshow(cm,cmap = plt.cm.Greens) ##繪製混淆矩陣圖,配色風格使用cm.Greens
plt.colorbar() ##顯示顏色標籤
# print(cm)
# print(len(cm))
###數據標籤
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") ##座標軸標籤
plt.show()
##繪製ROC曲線
predict_result = net.predict(test[:,:3]).reshape(len(test))
fpr,tpr,thresholds = roc_curve(test[:,3],predict_result,pos_label=1)
plt.plot(fpr,tpr,linewidth=2,label="ROC of LM") ##做出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()
6.2 CART決策樹模型構建及模型評價
CART決策樹模型構建及模型評價代碼如下所示:
#-*- coding:utf-8 -*-
import pandas as pd
from random import shuffle
from sklearn.metrics import confusion_matrix,roc_curve ##導入混淆矩陣,ROC曲線函數
from sklearn.tree import DecisionTreeClassifier ##導入決策樹模型
from sklearn.externals import joblib ##導入用來保存模型的模塊
import matplotlib.pyplot as plt
datafile = "F:\DeskTop\Python-Data\chapter6\demo\data\model.xls"
data = pd.read_excel(datafile)
data = data.as_matrix()
shuffle(data)
p = 0.8 #訓練數據佔總數據量的80%
train = data[:int(len(data)*p),:]
test = data[int(len(data)*p):,:]
#構建cart決策樹模型
treefile = "F:\DeskTop\Python-Data\chapter6\demo\data\lm_tree.model"
tree = DecisionTreeClassifier()
tree.fit(train[:,:3],train[:,3])
##保存模型
joblib.dump(tree,treefile)
"""
Scikit-Learn使用predict方法直接給出預測結果
"""
predict_result = tree.predict(train[:,:3])
cm = confusion_matrix(train[:,3],predict_result) ##得到混淆矩陣
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") ##座標軸標籤
plt.show()
##繪製ROC曲線
predict_result = tree.predict(train[:,:3])
fpr,tpr,thresholds = roc_curve(train[:,3],predict_result,pos_label=1)
plt.plot(fpr,tpr,linewidth=2,label="ROC of LM") ##做出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()
7.結果分析
利用訓練樣本構建LM神經網絡的混淆矩陣 |
利用訓練樣本構建CART決策樹的混淆矩陣 |
LM神經網絡在測試樣本下的ROC曲線 |
CART決策樹在測試樣本下的ROC曲線 |
LM神經網絡模型中,通過混淆矩陣可知,分類準確率爲(149+70)/ (149+70+5+8)=94.39%,正常用戶被誤判爲竊漏電用戶佔正常用戶的8/(149+8)=5.09%,竊漏電用戶被誤判爲正常用戶佔正常竊漏電用戶的5/(5+70)=6.66%。
CART決策樹模型中,通過混淆矩陣可知,分類準確率爲(164+56)/ (164+56+4+8)=94.82%,正常用戶被誤判爲竊漏電用戶佔正常用戶的8/(164+8)=4.65%,竊漏電用戶被誤判爲正常用戶佔正常竊漏電用戶的4/(4+56)=6.66%。
可見從準確率的角度,兩個模型的效果差不多。但是從ROC曲線可以看出,LM模型的曲線更加靠近單位方形的左上角,即ROC曲線下的面積(AUC)更大,說明LM神經網絡模型更優。
8.項目總結
通過“電力竊漏電用戶自動識別”項目:
(1)進一步熟悉了數據挖掘以及數據探索分析的一般流程;
(2)加深了對數據預處理中缺失值處理中,補全缺失值的拉格朗日插值法的理解;
(3)加深了對LM神經網絡模型CART決策樹模型的理解,進一步熟悉了Keras/Sklearn中相關函數的運用;
(4)提高了對混淆矩陣和ROC曲線這兩種模型評價指標的認識,進一步熟悉了Sklearn中相關函數的運用。
另外,代碼調試中遇到下述問題也可以爲以後的工作提供借鑑:
(1)TypeError: `Dense` can accept only 1 positional arguments ('units',), but you passed the following positional arguments: [3, 10]
解決辦法:
在Dense中寫好參數名稱: Dense(input_dim=3,output_dim=10),但上述修改方式仍然會提示警告:
UserWarning: Update your `Dense` call to the Keras 2 API: `Dense(input_dim=3, units=10)
故最終改爲Dense(input_dim=3,units=10)
(2)ValueError: ('Some keys in session_kwargs are not supported at this time: %s', dict_keys(['class_mode']))
解決辦法:
代碼中去掉class_mode='categorical'
(3)UserWarning: The `nb_epoch` argument in `fit` has been renamed `epochs`
修改代碼中的“nb_epoch”爲“epochs”即可