《Python数据分析与挖掘实战》第10章 热水器用户行为分析与事件识别

本文是《Python数据分析与挖掘实战》的实战部分的第10章的数据——《家用电器用户行为分析与事件识别》做的分析。

1.背景与挖掘目标

国内某智能热水器,在状态发生改变或有水流状态时会采集数据,该厂商根据采集到的数据进行用户行为分析,热水器不仅可以用来细雨还可以洗手、洗脸、刷牙、洗菜等。本案例基于热水器采集的时间序列数据,将顺序排列的离散的用水时间节点根据水流量和停顿时间间隔划分不同大小的时间区间,每个时间区间可以理解成一次完整用水事件。

挖掘目标:
第一,根据热水器采集到的数据,划分一次完整用水事件;
第二,划分好的完整用水事件中识别出洗浴事件。

部分原始数据:
《Python数据分析与挖掘实战》第10章 热水器用户行为分析与事件识别_第1张图片
2探索数据.
2.1 查看数据质量

import pandas as pd
import numpy as np
data = pd.read_excel('../data/original_data.xls',encoding='gbk')
data[u'发生时间'] = pd.to_datetime(data[u'发生时间'], format='%Y%m%d%H%M%S')  # 将该特征转成日期时间格式(***)
data = data[data[u'水流量'] > 0]  # 只要流量大于0的记录
# print len(data) #7679

data[u'用水停顿时间间隔'] = data[u'发生时间'].diff() / np.timedelta64(1, 'm')  # 将datetime64[ns]转成 以分钟为单位(*****)
data = data.fillna(0)  # 替换掉data[u'用水停顿时间间隔']的第一个空值
print(data.head())
data_explore = data.describe().T
data_explore['null'] = len(data)-data_explore['count']
explore = data_explore[['min','max','null']]
explore.columns = [u'最小值',u'最大值',u'空值数']
print(explore)

在这里插入图片描述

2.2用水事件划分

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

threshold = pd.Timedelta('4 min') #阈值为分钟
print(threshold)
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 #通过累积求和的方式为事件编号
print(data[u'事件编号'].head())
data.to_excel(outputfile)

2.3阈值寻优
利用阈值的斜率指标来作为某点的斜率指标

#阈值寻优
import numpy as np
import pandas as pd

inputfile = '../data/water_heater.xls' #输入数据路径,需要使用Excel格式
n = 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 #计算每两个相邻点对应的斜率
h[u'斜率指标'] = h[u'斜率'].abs().rolling(n).mean() #采用后n个的斜率绝对值平均作为斜率指标
ts = h[u'阈值'][h[u'斜率指标'].idxmin() - n]
#注:用idxmin返回最小值的Index,由于rolling_mean()自动计算的是前n个斜率的绝对值平均
#所以结果要进行平移(-n)

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

print(ts)

在这里插入图片描述

利用确定阈值的变化与划分得到的事件个数关系

or_data = pd.read_excel('../data/original_data.xls',encoding='gbk')
or_data.head()
data = or_data.drop(or_data.columns[[0,5,9]],axis=1) # 删掉不相关属性
data.to_excel('../data/test_data_guiyue.xlsx')
print(data.head())

timedeltalist = np.arange(2.25,8.25,0.25)
# 从2.25到8.25间,以间隔为0.25,确定阈值即,阈值范围为[2.25,2.5,2.75,3,...,7.75,8]
counts = [] # 记录不同阈值下的事件个数
for i in range(len(timedeltalist)):
    threshold = pd.Timedelta(minutes = timedeltalist[i])#阈值为四分钟
    data[u'发生时间'] = pd.to_datetime(data[u'发生时间'], format='%Y%m%d%H%M%S')
    d = data[u'发生时间'].diff() > threshold #  # 相邻时间做差分,比较是否大于阈值
    data[u'事件编号'] = d.cumsum() + 1 # 通过累积求和的方式为事件编号
    #print(data[u'事件编号'])
    temp = data[u'事件编号'].max()
    counts.append(temp)
coun = pd.Series(counts, index=timedeltalist)
print(coun)
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']= False
plt.rc('figure', figsize=(8,6))
np.set_printoptions(precision=4)
fig = plt.figure()
fig.set(alpha=0.2)#设置图标透明度
ax = fig.add_subplot(1,1,1)
# coun.plot(linestyle='-.',color='r',marker='<')
coun.plot(style='-.r*')#同上
ax.locator_params('x',nbins = int(len(coun)/2)+1)  # (****)
ax.set_xlabel(u'用水事件间隔阈值(分钟)')
ax.set_ylabel(u'事件数(个)')
ax.grid(axis='y',linestyle='--') # (****)
plt.savefig('threshold_numofCase.jpg')
plt.show()

《Python数据分析与挖掘实战》第10章 热水器用户行为分析与事件识别_第2张图片
由上图可知,图像趋势平缓说明用户的停顿习惯趋于稳定,所以取该段时间开始作为阈值,既不会将短的用水时间合并,也不会将长的用水时间拆开,因此,最后选取一次用水时间间隔阈值为4分钟

3构建模型
构建神经网络模型,在训练神经网络的时候选取了“候选洗浴事件”的11个属性作为网络的输入。分别为,洗浴时间点、总用水时长、总停顿时长、用水时长、总用水量、平均水流量、水流量波动和停顿时长波动。在训练神经网络的时候发现含二层隐层的神经网络训练效果较好,其中2个隐层的节点数分别为17,10,训练效果较好。

#建立、训练多层神经网络,并完成模型的检验
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].values #训练样本标签列
x_train = data_train.iloc[:,5:17].values #训练样本特征
y_test = data_test.iloc[:,4].values #测试样本标签列
x_test = data_test.iloc[:,5:17].values #测试样本特征

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

model = Sequential() #建立模型
model.add(Dense(input_dim=11, units=17)) #添加输入层、隐藏层的连接
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') #, class_mode="binary"

model.fit(x_train, y_train, epochs = 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)

predict_result_train = model.predict_classes(x_train).reshape(len(data_train)) #给出预测类别(训练集)
from cm_plot import * # 从编写好的包中导入画图函数
cm_plot(y_train, predict_result_train).show() #显示混淆矩阵可视化结果 看训练结果正确率

predict_result_test = model.predict_classes(x_test).reshape(len(data_test)) #给出预测类别(测试集)
cm_plot(y_test, predict_result_test).show() #显示混淆矩阵可视化结果 看测试结果正确率

训练混淆矩阵
《Python数据分析与挖掘实战》第10章 热水器用户行为分析与事件识别_第3张图片
测试混淆矩阵

《Python数据分析与挖掘实战》第10章 热水器用户行为分析与事件识别_第4张图片
testoutputfile:
《Python数据分析与挖掘实战》第10章 热水器用户行为分析与事件识别_第5张图片
因为训练数据比较小,不太准确,当数据量增大时,模型会越来越准确。

参考文章:https://blog.csdn.net/u012063773/article/details/79310068

你可能感兴趣的:(热水器用户行为分析与事件识别,python数据分析与挖掘实战)