《数据分析与挖掘 第十章 家用电器用户行为分析与事件识别》

家用电器用户行为分析与事件识别

数据抽取
首先对原始数据采用无放回的随机抽取
数据预处理
热水器编号对实验无实际性的意义,这个属性特征是可以删除的
有无水流可以用水流量来表示,因此这个属性是没有必要的
节能模式是一种模式,所有数据都是一样的,因此也是可以删去的属性
删去三种属性之后,留下九种属性

又,热水器“开关状态”为关的时候,“水流量”为0时,说明热水器不工作,此条数据是可以删除的

数据变化
除了筛选出这九个属性之外
在这里插入图片描述
我们还要知道每次使用水的行为,要区分几次流水的情况,是属于同一次用水行为,还是好几次用水行为,这就需要计算两次流水间隔时间,设定一个阈值T,如果间隔时间大于这个T值,就说明是两次用水事件,如果小于T,就说明是一次用水事件

下面对用水事件进行划分:

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

threshold = pd.Timedelta('4 min') #阈值为分钟
inputfile = 'water_heater.xls' #输入数据路径,需要使用Excel格式
outputfile = 'dividsequence.xls' #输出数据路径,需要使用Excel格式

data = pd.read_excel(inputfile)
#将时间字符串,变成时间的标准格式
data[u'发生时间'] = pd.to_datetime(data[u'发生时间'], format = '%Y%m%d%H%M%S')

将时间从20141019063917变成了2014-10-19 06:39:17

data = data[data[u'水流量'] > 0] #只要流量大于0的记录

从18840条记录中选出了7696条数据,这些事全部检测到在使用水的数据,相邻数据做差,既是时间间隔 data[u’发生时间’].diff() 求时间间隔

d = data[u'发生时间'].diff() > threshold #相邻时间作差分,比较是否大于阈值

d这是是一些列的bool类型值

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

threshold = pd.Timedelta('4 min') #阈值为分钟
inputfile = 'water_heater.xls' #输入数据路径,需要使用Excel格式
outputfile = '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
#cumsum()
#d.cumsum()求出来的是从0开始的,但是为了让第一件事件记为1,所以+1
#通过累积求和的方式为事件编号

data.to_excel(outputfile)

在这里插入图片描述
阈值的选取
我们事件的划分是根据两次流水之间的间隔时间阈值来看的,不同的阈值会导致划分事件的结果不同,那么该如何选取阈值呢,绘制阈值与事件个数的曲线,趋势平缓的部分,说明用户的停顿习惯趋于稳定,应该以该段时间开始作为阈值,选取曲线较为平缓的五个点,放大观看

阈值的优化
五个点出现四个斜率,算四段斜率绝对值的平均值K,作为最左端点的斜率指标
若K<1则,选这一段的坐左边的点A作为阈值
若K>=1且<5则用最小斜率指标的最左边的点作为阈值
若K>5,则直接以4作为阈值

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

inputfile = '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(n).mean()自动计算的是前n个斜率的绝对值平均
#所以结果要进行平移(-n)

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

print(ts)

dt是1-9分钟每隔0.25分钟取的阈值点:
[Timedelta(‘0 days 00:01:00’), Timedelta(‘0 days 00:01:15’), Timedelta(‘0 days 00:01:30’), Timedelta(‘0 days 00:01:45’), Timedelta(‘0 days 00:02:00’), Timedelta(‘0 days 00:02:15’), Timedelta(‘0 days 00:02:30’), Timedelta(‘0 days 00:02:45’), Timedelta(‘0 days 00:03:00’), Timedelta(‘0 days 00:03:15’), Timedelta(‘0 days 00:03:30’), Timedelta(‘0 days 00:03:45’), Timedelta(‘0 days 00:04:00’), Timedelta(‘0 days 00:04:15’), Timedelta(‘0 days 00:04:30’), Timedelta(‘0 days 00:04:45’), Timedelta(‘0 days 00:05:00’), Timedelta(‘0 days 00:05:15’), Timedelta(‘0 days 00:05:30’), Timedelta(‘0 days 00:05:45’), Timedelta(‘0 days 00:06:00’), Timedelta(‘0 days 00:06:15’), Timedelta(‘0 days 00:06:30’), Timedelta(‘0 days 00:06:45’), Timedelta(‘0 days 00:07:00’), Timedelta(‘0 days 00:07:15’), Timedelta(‘0 days 00:07:30’), Timedelta(‘0 days 00:07:45’), Timedelta(‘0 days 00:08:00’), Timedelta(‘0 days 00:08:15’), Timedelta(‘0 days 00:08:30’), Timedelta(‘0 days 00:08:45’)]

h:
在这里插入图片描述
因为每四个斜率作为五个点中最左边点的斜率指标,所以前四个点是没有斜率指标的

最后得出结果是4分钟作为阈值:
在这里插入图片描述
所以这里实际的实践过程应该是:先判断阈值,然后根据这个阈值,去对事件进行划分,然后得出哪些是用水事件

属性构造
由于我们现在要知道的是哪些事件是洗浴时间,所以我们不但要分辨出那些事用水事件,还要分离出这些事件里面的洗浴时间,这就需要再构造一些属性:
用水时长,用水量,水温

洗浴事件的特征:温度设定越高,水就越烫,兑的冷水多,热书使用就少,所以X与Y成反比的

根据热量守恒守恒,得到:
Y = (50 - C)*V/(X - C)

模型构建
这里假设已经将加上的一些属性计算好,并且已经添加到表格中了,现在对表格中数据进行训练:

from __future__ import print_function
import pandas as pd

inputfile1='train_neural_network_data.xls' #训练数据
inputfile2='test_neural_network_data.xls' #测试数据
testoutputfile = 'test_output_data5.xls' #测试数据模型输出文件
data_train = pd.read_excel(inputfile1) #读入训练数据(由日志标记事件是否为洗浴)
data_test = pd.read_excel(inputfile2) #读入测试数据(由日志标记事件是否为洗浴)

在这里插入图片描述
我们发现训练数据有28条,测试数据有21条,每条数据有16个属性,但是只有其中十一个属性是有意义的(是否为洗浴事件后面的11条),故选取十一个特征属性,将数据整理成x_train,y_train,x_test,y_test:

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 #测试样本特征

在这里插入图片描述
建立神经网络模型,这里对神经网络进行参数寻优,找到两层隐层神经网络比较好,并且两层隐层分别为17,10个节点,效果明显,好,就这么办:

建立模型

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 = 1) #训练模型
model.save_weights('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)

在这里插入图片描述
训练了100次:
在这里插入图片描述
保存了训练效果较好的一次结果模型
其实中间有的时候训练精度可能只有0.2几,这是因为训练数据太少的缘故,训练数据多一些,应该可以提升一下训练模型的精度

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值