1. 程式人生 > >家用電器使用者行為分析與事件識別程式碼詳解+修改後執行無誤的程式碼

家用電器使用者行為分析與事件識別程式碼詳解+修改後執行無誤的程式碼

執行環境:

ubuntu16.04 64位

pycharm python3.5.2

相關軟體列表:

cycler (0.10.0)
graphviz (0.7.1)
h5py (2.7.0)
Keras (2.0.4)
matplotlib (2.0.2)
numpy (1.12.1)
pandas (0.20.1)
pip (8.1.1)
protobuf (3.3.0)
pydot (1.2.3)
pyparsing (2.2.0)
python-dateutil (2.6.0)
pytz (2017.2)
PyYAML (3.12)
scipy (0.19.0)
setuptools (20.10.1)
six (1.10.0)
tensorflow (1.1.0)
Theano (0.9.0)
Werkzeug (0.12.2)
wheel (0.29.0)
xlrd (1.0.0)
xlwt (1.2.0)

-------------------------------------------------------------------下面是10-1-----------------------------------------------------------------------------------

#-*- coding: utf-8 -*-
#用水事件劃分
import pandas as pd

threshold = pd.Timedelta('4 min') #閾值為分鐘
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)

這個程式碼什麼意思呢?

也就是說,根據水流量和時間間隔的頻率來判斷使用者第幾次用水,舉個通俗的例子,就說洗菜把。

洗一顆青菜,洗一個葉子時需要用水對吧,但是呢,我把青菜的瓣兒一個個扳下來的這會兒功夫是不需要用水的對吧?

在扳的時候我停掉水龍頭,拌青菜完了之後開始洗了,就需要用水,然後洗下一個青菜,再停水。

那麼整個洗菜的過程中我有停水,也有用水,整個過程視為一次用水事件。

P205中表格的資料解釋:

可以看到

20141019172323

20141019172325

這兩個發生事件只相隔了2秒,水流量反而減少了,這個可以理解為水龍頭開大開小導致。

-------------------------------------------------------------------下面是10-2-----------------------------------------------------------------------------------

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

inputfile = '../data/water_heater.xls' #輸入資料路徑,需要使用Excel格式
n = 4 #使用以後四個點的平均斜率

threshold = pd.Timedelta(minutes = 5) #專家閾值,這句話就是把資料格式變化了下,沒有對資料進行處理
print("threshold=",threshold)
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):#這裡是函式定義,不是在執行,這裡的ts是threshold
  d = data[u'發生時間'].diff() > ts #相鄰時間作差分,比較是否大於閾值
  return d.sum() + 1 #這樣直接返回事件數
################以上程式碼和12-1類似################
dt = [pd.Timedelta(minutes = i) for i in np.arange(1, 9, 0.25)]#這裡用到的語法是列表推導,也叫作列表解析
#這裡arange用於建立等差陣列,這裡的資料最終會變化成時間資料格式,也就是說,這裡的0.25代表每分鐘的四分之一,也就是15秒,按照15秒為步長,進行取資料
#上面一句話的意思其實就是某某函式在某定義域的值的序列☆☆☆☆☆☆
h = pd.DataFrame(dt, columns = [u'閾值']) #定義閾值列
h[u'事件數'] = h[u'閾值'].apply(event_num) #計算每個閾值對應的事件數,呼叫了上面的event_num函式
#上面這句話的意思是在實現圖10-4,通過橫軸的閾值,來計算數軸的事件數

h[u'斜率'] = h[u'事件數'].diff()/0.25 #計算每兩個相鄰點對應的斜率
print("h[u'斜率'].abs()=",h[u'斜率'].abs())
h[u'斜率指標'] = pd.rolling_mean(h[u'斜率'].abs(), n) #採用後n個的斜率絕對值平均作為斜率指標
print("h[u'斜率指標']=",h[u'斜率指標'])
#以上的計算: h[u'斜率']=>h[u'斜率指標']
print("--------------------------------------------------------------------------------")



ts = h[u'閾值'][h[u'斜率指標'].idxmin() - n]#
#這裡ts得到的是4min,利用修正過後的索引對h[u'閾值']取值
#idxmin()返回陣列中最小值的索引
#注:用idxmin返回最小值的Index,由於rolling_mean()自動計算的是前n個斜率的絕對值平均(根據下方列表可以通透地理解這個意思)
#所以結果要進行平移(-n)
#這裡的平移其實是不太合適的,我認為平移n/2更加合理,因為一個點的斜率一般是取前後n/2個點進行平均計算後所得值是更為合理的。

if ts > threshold:#這裡的意思是,如果上面計算得到的ts小魚上面設定的專家閾值,就以ts為準,否則就降低為4.
  ts = pd.Timedelta(minutes = 4)#決定的最終的閾值
print("-----------------------------")
print("ts=",ts)

#所以這個程式碼的終極目的就是為了獲得斜率最低點的起始點,這樣有利於把前一件用水事件和後一件用水事件進行合理的區分。

這個程式碼的意思就是為了尋找書本p211的圖10-4的斜率為零的線段的起始點。

當線段下降很陡的時候,說明線段中的這幾個點很可能屬於同一個事件,所以化為一個事件。

同樣的,當線段很平坦,閾值的遞增對事件總數影響不大時,那麼曲線上的多個點代表的事件總是說明分類比較合理,也就是說此時每個用水事件之間相隔時間間隔較大。

-------------------------------------------------------------------下面是10-3-----------------------------------------------------------------------------------

接下來這個程式碼就是資料的輸入輸出之間進行模型訓練了,書上的程式碼沒辦法直接執行,我進行了修改,如下:

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


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
from keras.layers import Dense, Activation

model = Sequential() #建立模型
model.add(Dense(output_dim=17,input_dim=11)) #新增輸入層、隱藏層的連線
model.add(Activation('relu')) #以Relu函式為啟用函式

model.add(Dense(output_dim=10,input_dim=17)) #新增隱藏層、隱藏層的連線
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', class_mode="binary")

model.fit(x_train, y_train, nb_epoch = 100, batch_size = 1) #訓練模型
model.save_weights('../tmp/net.model') #儲存模型引數

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)
############自己新增的########################
plot_model(model, to_file='model.png', show_shapes=True)

程式碼執行結果為:

熱水事件 起始資料編號 終止資料編號 開始時間(begin_time) 根據日誌判斷是否為洗浴(1表示是,0表示否) 預測結果
0 1 73 336 2015-01-05 9:42:41' 1 1
1 2 420 535 '2015-01-05 18:05:28' 1 1
2 3 538 706 '2015-01-05 18:25:24' 1 1
3 4 793 910 '2015-01-05 20:00:42' 1 1
4 5 935 1133 '2015-01-05 20:15:13' 1 1
5 6 1172 1274 '2015-01-05 20:42:41' 1 1
6 7 1641 1770 '2015-01-06 08:08:26' 0 0
7 8 2105 2280 2015-01-06 11:31:13' 1 1
8 9 2290 2506 '2015-01-06 17:08:35' 1 1
9 10 2562 2708 '2015-01-06 17:43:48' 1 1
10 11 3141 3284 '2015-01-07 10:01:57' 0 1
11 12 3524 3655 2015-01-07 13:32:43' 0 1
12 13 3659 3863 '2015-01-07 17:48:22' 1 1
13 14 3937 4125 '2015-01-07 18:26:49' 1 1
14 15 4145 4373 '2015-01-07 18:46:07' 1 1
15 16 4411 4538 '2015-01-07 19:18:08' 1 1
16 17 5700 5894 2015-01-08 7:08:43' 0 1
17 18 5913 6178 2015-01-08 13:23:42' 1 1
18 19 6238 6443 2015-01-08 18:06:47' 1 1
19 20 6629 6696 2015-01-08 20:18:58' 1 1
20 21 6713 6879 2015-01-08 20:32:16' 1 1

注意每次預測結果都是不一樣的,上面的預測結果準確度是80%,如果多訓練幾次會發現準確度在60%~80%之間,靠右兩列數值不同時,則為判斷錯誤,相同時,則為判斷正確。

並且會出現隨機報錯,也就是說一次執行無報錯,另外一次執行報錯,屬正常現象,因為每次訓練都是區域性最優解。

使用的神經網路模型為: