[DM實戰]家用電器使用者行為分析與事件識別
1、家用企業若能深入瞭解不同使用者群的使用習慣,開發新功能,就能開拓新市場。廠商可從熱水器智慧操作和節能執行等多方面對產品進行優化。
熱水器廠商根據洗浴事件識別模型,對不同地區的使用者的用水進行識別,根據識別結果比較不同客戶群客戶群的客戶使用習慣、加深對客戶的理解等。從而,廠商可以給不同的客戶群提供最適合的個性化產品、改進新產品的智慧化的研發和制定相應的營銷策略。
根據提供的資料實現以下目標:
1)根據熱水器採集到的資料,劃分一次完整用水事件。
2)在劃分好的一次完整用水事件中,識別出洗浴事件。
2、對熱水使用者的歷史用水資料進行選擇性抽取,構建專家樣本。
本案例對原始資料採用無放回隨機抽樣法抽取200家熱水器使用者從2014年1月1日至2014年12月31日的用水記錄作為原始建模資料。
3、對步驟2)形成的資料集進行資料探索分析與預處理,包括探索用水事件時間間隔的分佈、規約冗餘屬性、識別用水資料的缺失值,並對缺失值進行處理,根據建模的需要進行屬性構造等。根據以上處理,對用水樣本資料建立用水事件時間間隔識別模型和劃分一次完整的用水事件模型,再在一次完整用水事件劃分結果的基礎上,剔除短暫用水事件,縮小識別範圍。
通過頻率分佈直方圖分析使用者用水停頓時間間隔的規律性,從而探究劃分一次完整用水事件的時間間隔閾值。
本案例的資料集的特點是資料量涉及上萬個使用者而且每個使用者每天的用水資料多達數萬條、存在缺失值、與分析主題無關的屬性或未直接反應用水事件的屬性等。在資料預處理階段,針對這些情況相應地應用了缺失值處理、資料規約和屬性構造等來解決這些問題。
4、在上一步得到的建模樣本資料基礎上,建立洗浴事件識別模型,對洗浴事件識別模型進行模型分析評價。
根據建模樣本資料和使用者記錄的包含用水的用途、用水開始時間、用水結束時間等屬性的用水日誌,建立多層神經網路模型識別洗浴事件。由於洗浴事件與普通用水事件在特徵上存在不同,而且這些不同的特徵在屬性上被體現出來。於是,根據使用者提供的用水日誌,將其中洗浴事件的資料狀態記錄作為訓練樣本訓練多層神經網路。然後根據訓練好的網路來檢驗新採集到的資料。
在訓練神經網路的時候,選取了“候選洗浴事件”的11個屬性作為網路的輸入。訓練BP網路時給定的輸出(教師訊號)為1與0,其中1代表該次事件為洗浴事件,0代表該次事件不是洗浴事件。其中。是否為洗浴事件根據使用者提供的用水記錄日誌得到。
在訓練神經網路時,對神經網路的引數進行尋優,發現含兩個隱層的神經網路訓練效果較好,其中兩個隱層的隱節點數分別為17、10時訓練的效果較好。
5、對上一步形成的模型結果應用並對洗浴事件劃分進行優化。
6、呼叫洗浴事件識別模型,對實時監控的熱水器流水資料進行洗浴事件自動識別。
#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') #將表格中對應的列資料轉化成datetime格式
data = data[data[u'水流量'] > 0] #只要流量大於0的記錄
d = data[u'發生時間'].diff() > threshold #相鄰時間作差分,比較是否大於閾值
#記錄編號 是否大於閾值
# 2 False
# 56 True
# 381 True
# .....
data[u'事件編號'] = d.cumsum() + 1 #通過累積求和的方式為事件編號 cumsum()計算軸向元素累加和,返回由中間結果組成的陣列
print("cumsum:", d.cumsum()+1)
#記錄編號 事件編號
# 2 1
# 56 2
# 381 3
# 382 3
# .....
data.to_excel(outputfile)
#coding:utf-8
#閾值尋優
import numpy as np
import pandas as pd
inputfile = './data/water_heater.xls' #輸入資料路徑,需要使用excel格式
n = 4 #使用以後4個點的平均斜率
threshold = pd.Timedelta(minutes=5) #專家閾值 表示兩個datetime值之間的差(日、秒、毫秒)
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 #計算每兩個相鄰點對應的斜率
h[u'斜率指標'] =pd.rolling_mean(h[u'斜率'].abs(),n) #採用後n個的斜率絕對值平均作為斜率指標
ts = h[u'閾值'][h[u'斜率指標'].idxmin() - n]
#注:用idxmin返回最小值的index,由於rolling_mean()自動計算的是前n個斜率的絕對值,所以結果要進行評議(-n)
if ts>threshold:
ts = pd.Timedelta(minutes=4)
print(ts)
#coding:utf-8
#建立、訓練多層神經網路,並完成模型的檢驗
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, units=7)) #新增輸入層、隱藏層的連線
model.add(Activation('relu')) #以Relu函式為啟用函式
model.add(Dense(input_dim=17, units=10)) #新增隱藏層、隱藏層的連線
model.add(Activation('relu')) #以relu函式為啟用函式
model.add(Dense(input_dim=10, units=1)) #新增隱藏層、輸出層的連線
model.add(Activation('sigmoid')) #以sigmoid函式為啟用函式
#編譯模型,損失函式為binary_crossentropy,用adam法求解
model.compile(loss='binary_crossentropy', optimizer='adam')
model.fit(x_train, y_train, nb_epoch=100, batch_size=1) #訓練模型 迴圈100次 批尺寸為1(每次只訓練一個樣本,即 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)
# 1/28 [>.............................] - ETA: 0s - loss: 1.1921e-07
# 28/28 [==============================] - 0s 673us/step - loss: 1.8440
參考自:《python資料分析與挖掘》 --張良均