Pyhton--家用電器用戶行爲分析與事件識別--多層神經網絡

問題背景

如果你是一個家電公司的,你要賣熱水器,但是不同的地區氣候、不同區域、用戶的差別都會導致使用不同,你爲了能因地制宜,因人而異的掙更多錢,你需要了解用戶的熱水器使用習慣。由於你們公司熱水器能記錄用戶熱水器的溫度,開機,加熱等狀態數據,所以你獲得了原始的一些熱水器數據。
數據來源:
https://github.com/apachecn/python_data_analysis_and_mining_action/tree/master/chapter10/data

挖掘目標

  1. 根據熱水器採集到的數據,劃分一次完整用水事件
  2. 在劃分好的一次完整用水事件中,識別出洗浴事件

這屬於識別分類 0-1二分類問題與實踐一中偷電用戶的識別相類似,不過數據更難以處理。

數據提取

  • 智能熱水器在狀態發生改變或者水流量非零時,每兩秒會採集一條狀態數據。
  • 本案例抽取200家熱水器用戶從2014年1月1日至2014年12月31日的用水記錄。
    在這裏插入圖片描述

數據探索

用水停頓時間間隔爲一條流量不爲0的流水記錄同下一條水流量不爲0的流水記錄之間的時間間隔
在這裏插入圖片描述
上表可知,停頓時間間隔爲0-0.3分鐘的頻率很高,根據日常用水經驗可以判斷爲一次用水事件中的停頓;停頓時間爲6-13分鐘的頻率較低,分析其爲兩次用水事件之間的停頓間隔。兩次用水事件的停頓時間間隔分佈在3-7分鐘。

數據預處理

數據規約

  • 屬性規約:去除“機器編號”、“有無水流”(水流量可以表示)、“節能模式”(都爲關)
  • 數值規約:“開關機狀態”爲“關”且水流量爲0時,說明熱水器不處於工作狀態,數據記錄可以刪除

數據變換

本案例首先需要從原始記錄中劃分哪些連續的記錄是一次完整的用水事件,一次完整的用水事件是根據水流量和停頓時間間隔的閾值去劃分的,所以還建立閾值尋優模型
在這裏插入圖片描述

一次完整用水事件的劃分模型

在用水記錄中,水流量不爲0表示正在使用熱水;水流量爲0是用戶用水發生停頓或者用水結束。如果水流量爲0的記錄之間的時間間隔超過一個閾值T,則劃分爲一個用水事件
在這裏插入圖片描述
一次完整用水事件的劃分步驟如下:

  1. 讀取數據記錄,識別到第一條水流量不爲0的數據記錄記爲R1,按順序識別接下來的一條水流量不爲0的數據記錄R2
  2. 若gapi>T,則Ri+1與Ri及之間的數據記錄不能劃分到同一次用水事件。同時將Ri+1記錄作爲新的讀取數據記錄的開始,返回步驟1);若gap_i<T,則將R_{i+1}與R_i及之間的數據記錄劃分到同一次用水事件,並記錄截接下來的水流了不爲0數據記錄爲R_{i+2}$
  3. 循環執行步驟2),直到數據記錄讀取完畢,結束事件劃分。 Python代碼實現用水事件的劃分:
#-*- coding:utf-8 -*-
#用水事件劃分
import pandas as pd

threshold=pd.Timedelta(minutes=4) #閾值爲4分鐘
inputfile='../data/water_heater.xls' #輸入數據路徑,需要使用excel格式
outputfile='../tmp/dividsequence.xls' #輸出數據路徑,需要使用excel格式

data=pd.read_excel(inputfile)
data[u'發生時間']=pd.to_datetime(data[u'發生時間'],format='%Y%m%d%H%M%S')
data=data[data[u'水流量']>0] #只要水流量大於0的記錄
d=data[u'發生時間'].diff()>threshold #相鄰時間做差分,比較是否大於閾值
data[u'事件編號']=d.cumsum()+1

data.to_excel(outputfile)

劃分結果如下:
在這裏插入圖片描述

用水事件閾值尋優模型

不同地區、不同人、不同季節用水習慣不相同,停頓時長不相同導致閾值差異,建立閾值尋優模型來更新尋找最優的閾值,將事件劃分更加合理
在這裏插入圖片描述
閾值事件個數在某個閾值區間內趨於穩定,可以取該段開始閾值(及其後4個點)進行斜率尋優
在這裏插入圖片描述
K可以作爲A點的斜率指標。
於是,閾值優化過程如下:

當K<1,則取閾值最小的點A,把它的閾值作爲劃分事件的標準(其中1是專家閾值)
當不存在K<1是,則找所有閾值中斜率指標K最小的閾值;如果該最小K小於5,則取該閾值作爲標準;若該最小K不小於5,則取專家默認閾值4分鐘。

#-*- coding:utf-8 -*-
#閾值尋優
import numpy as np
import pandas as pd

inputfile='../data/water_heater.xls'#輸入數據路徑
n=4#使用以後4個點的平均斜率

threshold=pd.Timedelta(minutes=5) #專家閾值
data=pd.read_excel(inputfile)
data[u'發生時間']=pd.to_datetime(data[u'發生時間'],format='%Y%m%d%H%M%S')
data=data[data[u'水流量']>0] #只要水流量大於0的記錄

def event_num(ts):
    d=data[u'發生時間'].diff()>ts #相鄰事件做查分,比較是否大於閾值
    return d.sum()+1 #這樣直接返回時間數

dt=[pd.Timedelta(minutes=i) for i in np.arange(1,9,0.25)]
h=pd.DataFrame(dt,columns=[u'閾值']) #定義閾值列
h[u'事件數']=h[u'閾值'].apply(event_num) #計算每個閾值對應的事件個數,閾值作爲參數傳禁區
h[u'斜率']=h[u'事件數'].diff()/0.25 #計算每兩個相鄰點對應的斜率,每兩個相鄰點相差0.25
h[u'斜率指標'] =h[u'斜率'].abs().rolling(n).mean() #採用後n個斜率的絕對值平均作爲斜率指標

ts=h[u'閾值'][h[u'斜率指標'].idxmin()-n]
#注:用idmin返回最小值的index,由於rolling_mean()自動計算的是前n個斜率的絕對值平均
#所以結果要進行平移(-n)

if ts>threshold:
    ts=pd.Timedelta(minutes=4)

print(ts)

尋優結果如下:最優閾值4分鐘
0 days 00:04:00

屬性構造

本案例研究的是用水行爲,可以構造4類指標來進行模型的訓練:時長指標、頻率指標、用水的量化指標以及用水的波動指標,計算如下:
在這裏插入圖片描述
在這裏插入圖片描述

篩選得“候選洗浴事件”

首先,用3個比較寬鬆的條件篩選掉哪些非常短暫的用水事件:

  • 一次用水事件中總用水量(純熱水)小於y升
  • 用水時長小於100秒
  • 總用水時長小於120秒

其次,對y的合理取值進行探究。
在這裏插入圖片描述
在這裏插入圖片描述

數據清洗

一次完整的用水事件,需要一個開始用水的狀態記錄和結束用水的狀態記錄。但是,在劃分一次完整用水事件時,發現數據中存在沒有結束用水的狀態情況
在這裏插入圖片描述
如圖,第5條狀態和第7條狀態記錄的事件間隔應爲2秒,而表中間隔太大。
該類缺失值的處理如下:
在存在用水狀態記錄缺失的情況下,填充一條狀態記錄使水流量爲0,發生時間加2秒,其餘屬性狀態不變。
在這裏插入圖片描述

模型構建

本次使用多層神經網絡,詳情介紹請點擊神經網絡算法,建模樣本數據如下:
在這裏插入圖片描述
模型選擇:11個屬性作爲輸入,含有兩個隱含層的神經網絡,隱節點數分別爲17,10時訓練最優,輸出爲1表示爲洗浴事件,輸出爲0表示不是洗浴事件。
在這裏插入圖片描述

#-*- coding:utf-8 -*-
#建立、訓練多層神經網絡,並完成模型的檢驗
from __future__ import print_function
import pandas as pd

inputfile1='../data/train_neural_network_data.xls' #訓練數據
inputfile2='../data/test_neural_network_data.xls' #測試數據
testoutputfile='../tmp/test_output_data.xls' #測試數據模型輸出文件
data_train=pd.read_excel(inputfile1) #讀入訓練數據(由日誌標記時間是否爲洗浴)
data_test=pd.read_excel(inputfile2) #讀入測試數據(有日誌標記時間是否爲洗浴)
y_train=data_train.iloc[:,4].as_matrix() #訓練樣本標籤列
x_train=data_train.iloc[:,5:17].as_matrix() #訓練樣本特徵
y_test=data_test.iloc[:,4].as_matrix() #測試樣本標籤列
x_test=data_test.iloc[:,5:17].as_matrix() #測試樣本特徵

from keras.models import Sequential
from keras.layers.core import Dense,Dropout,Activation

model = Sequential() #建立模型
model.add(Dense(input_dim=11,output_dim=17))#添加輸入層、隱藏層的連接
model.add(Activation('relu')) #以Relu函數爲激活函數
model.add(Dense(input_dim=17,output_dim=10)) #添加隱藏層、隱藏層的鏈接
model.add(Activation('relu')) #以Relu函數爲激活函數
model.add(Dense(input_dim=10,output_dim=1))  #添加隱藏層、輸出層的連接
model.add(Activation('sigmoid')) #以sigmoid函數爲激活函數

#編譯模型,損失函數爲binary_crossentropy,用adam法求解
model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])

model.fit(x_train,y_train,nb_epoch=100,batch_size=2) #訓練模型 batch=2時準確率85.7
model.save_weights('../tmp/net.model') #保存模型參數
'''
#導入訓練好的model weights
weight_file='../tmp/net.model'
model.load_weights(weight_file)
'''
r=pd.DataFrame(model.predict_classes(x_test),columns=[u'預測結果'])
pd.concat([data_test.iloc[:,:5],r],axis=1).to_excel(testoutputfile)
model.predict(x_test)

模型評價

該模型預測結果比較如下,總共識別了21條數據,準確識別了18條數據,正確率爲85.7%,由於訓練樣本較少,可能不準確,但是因爲長期記錄用戶用水日誌比較困難,模型檢驗用了兩週的數據。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章