實戰-電力竊露漏電使用者自動識別

西西嘛呦發表於2020-09-18

問題描述:判斷使用者是否竊漏電

問題解決:二分類問題

缺失值:拉格朗日插值法進行填充

使用的特徵:電量趨勢下降指標、線損指標、警告類指標

這裡使用的資料來<python資料分析與實戰第六章>

資料:

程式碼實現:

1、載入資料

import pandas as pd
from random import shuffle

datafile = path + 'chapter6/model.xls'
data = pd.read_excel(datafile)

2、劃分訓練集和測試集

#data = data.as_matrix() 舊版本的pandas是這麼使用的,將dataframe轉換為矩陣
data = data.iloc[:,:].values #新版本這麼使用
shuffle(data)

p = 0.8 #設定訓練資料比例
train = data[:int(len(data)*p),:]
test = data[int(len(data)*p):,:]

3、使用keras定義模型

from keras.models import Sequential #匯入神經網路初始化函式
from keras.layers.core import Dense, Activation #匯入神經網路層函式、啟用函式

netfile = path + 'chapter6/net.model' #構建的神經網路模型儲存路徑

net = Sequential() #建立神經網路
net.add(Dense(3, 10)) #新增輸入層(3節點)到隱藏層(10節點)的連線
net.add(Activation('relu')) #隱藏層使用relu啟用函式
net.add(Dense(10, 1)) #新增隱藏層(10節點)到輸出層(1節點)的連線
net.add(Activation('sigmoid')) #輸出層使用sigmoid啟用函式
net.compile(loss = 'binary_crossentropy', optimizer = 'adam', class_mode = "binary") #編譯模型,使用adam方法求解

net.fit(train[:,:3], train[:,3], nb_epoch=100, batch_size=1) #訓練模型,迴圈100次
net.save_weights(netfile) #儲存模型

由於keras版本導致的錯誤:

常見錯誤(均是因為keras版本改動)

  • TypeError: Dense can accept only 1 positional arguments ('units',), but you passed the following positional arguments: [23, 34]
  • 解決方法:在Dense中寫好引數名稱改為Dense(input_dim=23,units=34)
  • ValueError: ('Some keys in session_kwargs are not supported at this time: %s', dict_keys(['class_mode']))
  • 解決方法:模型編譯程式碼中去掉class_mode這一屬性
  • UserWarning: The nb_epoch argument in fit has been renamed epochs

    解決方法:

    修改程式碼中的“nb_epoch”為“epochs”即可

修改後的程式碼:

from keras.models import Sequential #匯入神經網路初始化函式
from keras.layers.core import Dense, Activation #匯入神經網路層函式、啟用函式

netfile = path + 'chapter6/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=100, batch_size=1) #訓練模型,迴圈100次
net.save_weights(netfile) #儲存模型

部分結果:

Epoch 97/100
232/232 [==============================] - 1s 3ms/step - loss: 0.3171
Epoch 98/100
232/232 [==============================] - 1s 3ms/step - loss: 0.3196
Epoch 99/100
232/232 [==============================] - 1s 3ms/step - loss: 0.3194
Epoch 100/100
232/232 [==============================] - 1s 3ms/step - loss: 0.3144

我們也可以訓練時加入更多的評價指標:(二分類指標)

具體的評價指標的使用可參考文件:

https://keras.io/api/metrics/classification_metrics/#precision-class

import tensorflow as tf
import numpy as np
#精確率評價指標
from keras.models import Sequential #匯入神經網路初始化函式
from keras.layers.core import Dense, Activation #匯入神經網路層函式、啟用函式

netfile = path + 'chapter6/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', 
            metrics=['accuracy',
            tf.keras.metrics.Precision(),
            tf.keras.metrics.Recall()]) #編譯模型,使用adam方法求解

net.fit(train[:,:3], train[:,3], epochs=100, batch_size=1) #訓練模型,迴圈1000次
net.save_weights(netfile) #儲存模型

部分結果:

Epoch 97/100
232/232 [==============================] - 1s 4ms/step - loss: 0.1729 - accuracy: 0.9526 - precision: 0.8902 - recall: 0.8770
Epoch 98/100
232/232 [==============================] - 1s 4ms/step - loss: 0.1740 - accuracy: 0.9526 - precision: 0.8908 - recall: 0.8774
Epoch 99/100
232/232 [==============================] - 1s 4ms/step - loss: 0.1693 - accuracy: 0.9569 - precision: 0.8910 - recall: 0.8780
Epoch 100/100
232/232 [==============================] - 1s 4ms/step - loss: 0.1750 - accuracy: 0.9526 - precision: 0.8915 - recall: 0.8783

對模型進行驗證:

scores = net.evaluate(test[:,:3], test[:,3], verbose=0)
for i in range(1,len(net.metrics_names)):
  print("%s: %.2f%%" % (net.metrics_names[i], scores[i]*100)) # 列印出驗證集準確率

accuracy: 88.14%

precision: 89.14%

recall: 87.85%

使用模型進行預測:這裡注意有兩個api,一個得到的是概率值,另一個得到的是類別:

使用predict()得到的是概率值:這裡將其用round進行四捨五入後進行展開。

predict_result = tf.round(net.predict(test[:,:3]).reshape(len(test)))
with tf.Session() as sess:
  print(predict_result.eval())

[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 1. 0. 0. 1. 0. 0. 1. 1. 1. 1. 0. 0. 1. 1. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 1. 0. 0. 0.]

使用predict_classes()得到的是類別:

predict_result2 = net.predict_classes(test[:,:3]).reshape(len(test))
predict_result2 

array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0], dtype=int32)

列印一下真實的標籤:

y_true = np.array(test[:,3])

array([0, 0, 0, 0, 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, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

4、評價指標的計算方式以及混淆矩陣

我們可以直接通過sklearn api來計算評價指標:

from sklearn.metrics import classification_report
target_names = ['no','yes']
print(classification_report(test[:,3],predict_result2,target_names=target_names))

結果:

              precision    recall  f1-score   support

          no       0.98      0.88      0.93        50
         yes       0.57      0.89      0.70         9

    accuracy                           0.88        59
   macro avg       0.77      0.88      0.81        59
weighted avg       0.92      0.88      0.89        59

或者我們可以通過混淆矩陣自己來計算:首先是獲得混淆矩陣

from sklearn.metrics import confusion_matrix
cnf_matrix = confusion_matrix(test[:,3], predict_result2)
print(cnf_matrix)
#行、列的索引就是標籤id,這裡有兩類,用0,1,表示
[[44 6] [ 1 8]]

混淆矩陣中的四個值分別代表TP、FP、TN、PN

根據混淆矩陣,我們可以計算二分類評價指標:(標籤為1的是正樣本,因此TP是[1][1])

TP=cnf_matrix[1][1] #預測為正的真實標籤為正
FP=cnf_matrix[0][1] #預測為正的真實標籤為負
FN=cnf_matrix[1][0] #預測為負的真實標籤為正
TN=cnf_matrix[0][0] #預測為負的真實標籤為負
accuracy=(TP+TN)/(TP+FP+FN+TN)
precision=TP/(TP+FP)
recall=TP/(TP+FN)
f1score=2 * precision * recall/(precision + recall)
print(accuracy,precision,recall,f1score)

0.8813559322033898 0.5714285714285714 0.8888888888888888 0.6956521739130435

這也上面api計算的yes的評價指標的值一致。

5、繪製混淆矩陣

import matplotlib.pyplot as plt 
%matplotlib inline
def cm_plot(y, yp, labels_name):
  
  from sklearn.metrics import confusion_matrix #匯入混淆矩陣函式

  cm = confusion_matrix(y, yp) #混淆矩陣
  
  plt.matshow(cm, cmap=plt.cm.Greens) #畫混淆矩陣圖,配色風格使用cm.Greens,更多風格請參考官網。
  plt.colorbar() #顏色標籤
  num_local = np.array(range(len(labels_name))) 
  plt.xticks(num_local, labels_name)    # 將標籤印在x軸座標上
  plt.yticks(num_local, labels_name)    # 將標籤印在y軸座標上

  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
cm_plot(test[:,3],predict_result2,['no', 'yes']).show()

6、二分類其他評價指標(這兩個我重新在colab上執行的,因此資料和上面不一樣)

ROC曲線:

橫座標:假正率(False positive rate, FPR),預測為正但實際為負的樣本佔所有負例樣本的比例;

FPR = FP / ( FP +TN)   

縱座標:真正率(True positive rate, TPR),這個其實就是召回率,預測為正且實際為正的樣本佔所有正例樣本的比例。

TPR = TP / ( TP+ FN) 

AUC:就是roc曲線和橫座標圍城的面積。

如何繪製?

對於二值分類問題,例項的值往往是連續值,通過設定一個閾值,將例項分類到正類或者負類(比如大於閾值劃分為正類)。上述中我們直接利用四捨五入來區分正類和負類。因此,可以變化閾值,根據不同的閾值進行分類,根據分類結果計算得到ROC空間中相應的點,連線這些點就形成ROC curve。ROC curve經過(0,0) (1,1),實際上(0,0)和(1,1)連線形成的ROC curve實際上代表的是一個隨機分類器。一般情況下,這個曲線都應該處於(0,0)和(1,1)連線的上方,

程式碼實現:

from sklearn.metrics import roc_curve, auc
# 為每個類別計算ROC曲線和AUC
predict_res=net.predict(test[:,:3]).reshape(len(test))
fpr,tpr,threholds=roc_curve(test[:,3],predict_res,pos_label=1)
roc_auc=auc(fpr,tpr)
plt.plot(fpr,tpr,linewidth=2, label='ROC curve (area = %0.2f)' % roc_auc)
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()

繪製Precision-Recall曲線:

from sklearn.metrics import precision_recall_curve
from sklearn.metrics import average_precision_score
precision,recall,_ = precision_recall_curve(test[:,3],predict_res,pos_label=1)
average_precision = average_precision_score(test[:,3],predict_res,pos_label=1)
plt.plot(recall, precision,label='Precision-recall curve of class (area = {1:0.2f})'.format(i, average_precision))
plt.xlabel('Recall', fontsize=16)
plt.ylabel('Precision',fontsize=16)
plt.title('Extension of Precision-Recall curve to 2-class',fontsize=16)
plt.legend(loc="upper right")#legend 是用於設定圖例的函式
plt.show()

關於二分類評價指標網上已經有很多講解的很清楚的了,就不仔細講了,還是注重實際的程式碼。本來是應該對比不同的模型的,結果搞成了講解二分類指標了。。。 

 

參考:

《python資料分析與挖掘實戰》 

https://www.cnblogs.com/liweiwei1419/p/9870034.html

https://blog.csdn.net/weixin_39541558/article/details/82708832

相關文章