9 家用热水器用户行为分析与事件识别

news2024/11/25 11:00:42

第9章 家用热水器用户行为分析与事件识别

  • 9.1 了解家用热水器用户行为分析的背景与步骤
    • 9.1.1 热水器采集数据基本情况
    • 9.1.2 熟悉家用热水器用户行为分析的步骤与流程
  • 9.2 预处理热水器用户用水数据
    • 9.2.1 删除冗余特征
    • 9.2.2 划分用水事件
    • 9.2.3 确定单次用水事件时长阈值
    • 9.2.4 代码
      • 1、删除冗余特征
      • 2、 划分用水事件
      • 3、确定单次用水事件时长阈值
  • 9.3 构建用水行为特征并筛选用水事件
    • 9.3.1 构建用水时长与频率特征
    • 9.3.2 构建用水量与波动特征
    • 9.3.3 筛选候选洗浴事件
    • 9.3.4 代码: 构建用水时长与频率特征;构建用水量与波动特征;筛选候选洗浴事件
  • 9.4 构建行为事件分析的BP神经网络模型
    • 9.4.1 了解BP神经网络算法原理
      • 1、原理概述
      • 2、优缺点与应用领域
      • 3、主要参数介绍
    • 9.4.2 构建模型
    • 9.4.3 评估模型
    • 9.4.4 代码:构建并评价神经网络模型
  • 9.5 小结

9.1 了解家用热水器用户行为分析的背景与步骤

9.1.1 热水器采集数据基本情况

  国内某热水器生产厂商新研发的一种高端智能热水器,在状态发生改变或者有水流状态时,会采集各项数据。抽取200个热水器用户的用水记录作为原始建模数据,热水器采集到用户用水数据如下表所示。
在这里插入图片描述
  热水器采集的用水数据包含12个特征:热水器编码,发生时间,开关机状态,加热中,保温中,有无水流,实际温度,热水量,水流量,节能模式,加热剩余时间和当前设置温度。其解释说明如下表所示。
在这里插入图片描述

9.1.2 熟悉家用热水器用户行为分析的步骤与流程

  在热水器用户行为分析过程中,用水事件识别是最为关键的环节。根据该热水器生产厂商提供的数据热水器用户用水事件划分与识别项目的整体目标如下。
  (1)根据热水器采集到的数据,划分一次完整用水事件。
  (2)在划分好的一次完整用水事件中,识别出洗浴事件。
热水器用户事件划分与识别项目的总体流程图:
在这里插入图片描述
  热水器用户用水事件划分与识别项目主要包括以下5个步骤。
  ① 对热水用户的历史用水数据进行选择性抽取,构建专家样本。
  ② 对①形成的数据集进行数据探索分析与预处理,包括探索用水事件时间间隔的分布,删除冗余特征,识别用水数据的缺失值,并对缺失值作处理,根据建模的需要进行特征构造等。根据以上处理,对用水样本数据建立用水事件时间间隔识别模型和划分一次完整的用水事件模型,再在一次完整用水事件划分结果的基础上,剔除短暂用水事件缩小识别范围等。
  ③ 在②得到的建模样本数据基础上,建立洗浴事件识别模型,对洗浴事件识别模型进行模型分析评价。
  ④ 对③形成的模型结果应用并对洗浴事件划分进行优化。
  ⑤ 调用洗浴事件识别模型,对实时监控的热水器流水数据进行洗浴事件自动识别。

9.2 预处理热水器用户用水数据

9.2.1 删除冗余特征

  由于热水器采集的用水数据特征较多,本项目特征删除对分析无影响的特征。因分析的主要对象为用户,分析的主要目标为用户洗浴行为的一般规律,所以“热水器编号”特征可以去除:在热水器采集的数据中,“有无水流”特征可以通过“水流量”特征反应,“节能模式”特征取值相同,均为“关”,对分析无作用,可以去除。最终用来建模的特征如下表所示。
在这里插入图片描述

9.2.2 划分用水事件

  为了探究用户真实用水停顿时间间隔的分布情况,通过频率分布表分析用户用水停顿时间间隔的规律性,从而探究划分一次完整用水事件的时间间隔阈值。具体的数据如下表所示。
在这里插入图片描述

  分析上表可知:

  • 停顿时间间隔为0~0.3分钟的频率很高,根据日常用水经验可以判断其为一次用水时间中的停顿。
  • 停顿时间间隔为6~13分钟的频率较低,分析其为两次用水事件之间的停顿间隔。
  • 两次用水事件的停顿时间间隔分布在3~7分钟。
    根据现场实验统计用水停顿的时间间隔近似。

  用户的用水数据存储在数据库中,记录了各种各样的用水事件,包括洗浴,洗手,刷牙,洗脸,洗衣,洗菜等,而且一次用水事件由数条甚至数千条的状态记录组成。所以本项目首先需要在大量的状态记录中划分出哪些连续的数据是一次完整的用水事件。
  用水状态记录中,水流量不为0表明用户正在使用热水;而水流量为0时用户用热水发生停顿或者用热水结束。对于任一个用水记录,如果它的向前时差超过阈值T,则将它记为事件的开始编号;如果向后时差超过阈值T ,则将其记为事件的结束编号。划分模型的符号说明如下表。
在这里插入图片描述
  一次完整用水事件的划分步骤如下:
  ① 读取数据记录,识别到所有水流量不为0的状态记录,将它们的发生时间记为序列t1。
  ② 对序列t1构建其向前时差列和向后时差列,并分别与阈值进行比较。向前时差超过阈值T,则将它记为新的用水事件的开始编号;如果向后时差超过阈值T,则将其记为用水事件的结束编号。
  ③ 循环执行步骤②直到向前时差列和向后时差列与均值比较完毕,结束事件划分。

对用户的用水数据进行划分结果如下表所示。
在这里插入图片描述

9.2.3 确定单次用水事件时长阈值

对某热水器用户的数据根据不同的阈值划分用水事件,得到了相应的事件个数,阈值变化与划分得到事件个数如下。
在这里插入图片描述

  • 图中某段阈值范围内,下降趋势明显,说明在该段阈值范围内,用户的停顿习惯比较集中。
  • 如果趋势比较平缓,则说明用户的停顿热水的习惯趋于稳定,所以取该段时间开始的时间点作为阈值,既不会将短的用水事件合并,又不会将长的用水事件拆开。
  • 在上图中,用户停顿热水的习惯在方框的位置趋于稳定,说明热水器用户的用水的停顿习惯用方框开始的时间点作为划分阈值会有一个好的效果。

  曲线在上图中方框趋于稳定时,其方框开始的点的斜率趋于一个较小的值。为了用程序来识别这一特征,将这一特征提取为规则。根据下图说明如何识别上图方框中的起始的时间。
在这里插入图片描述
  每个阈值对应一个点,给每个阈值计算得到一个斜率指标,如上图所示。其中, A 点是要计算的斜率指标点。为了直观的展示,用下表所示的符号来进行说明。
在这里插入图片描述
在这里插入图片描述
  将K作为A点的斜率指标,特别指出横坐标上的最后四个点没有斜率指标,因为找不出在它以后的4个更长的阈值。但这不影响对最优阈值的寻找,因为可以提高阈值的上限,以使最后的4个阈值不是考虑范围内的阈值。
  阈值优化的结果如下∶
  (1)当存在一个阈值的斜率指标K<1时,则取阈值最小的点A(可能存在多个阈值的斜率指标小于1 )的横坐标xA作为用水事件划分的阈值,其中K<1中的“1”是经过实际数据验证的一个专家阈值。
  (2)当不存在K<1时,则找所有阈值中斜率指标最小的阈值; 如果该阈值的斜率指标小于5,则取该阈值作为用水事件划分的阈值; 如果该阈值的斜率指标不小于5,则阈值取默认值的阈值4分钟。其中斜率指标小于5中的“5”是经过实际数据验证的一个专家阈值。

9.2.4 代码

1、删除冗余特征

# 代码 9-1 删除冗余特征
import pandas as pd
data = pd.read_excel('F:/书籍/Python数据分析与应用/df/original_data.xls')
print('初始状态的数据形状为:', data.shape)
# 删除热水器编号,有无水流,节能模式
data.drop(labels=["热水器编号", "有无水流", "节能模式"], axis=1, inplace=True)
print('删除冗余特征后的数据形状为:', data.shape)
data.to_csv('F:/书籍/Python数据分析与应用/df/water_heart.csv', index=False)

在这里插入图片描述

2、 划分用水事件

# 代码 9-2 划分用水事件
import numpy as np
import pandas as pd
data = pd.read_excel('F:/书籍/Python数据分析与应用/df/original_data.xls')
threshold = pd.Timedelta('4 min') # 阈值为分钟
data['发生时间'] = pd.to_datetime(data['发生时间'], format='%Y%m%d%H%M%S')  # 转换时间格式
data = data[data['水流量'] > 0]  # 只要流量大于0的记录
# 相邻时间向前差分,比较是否大于阈值
sjKs = data['发生时间'].diff() > threshold
sjKs.iloc[0] = True  # 令第一个时间为第一个用水事件的开始事件
sjJs = sjKs.iloc[1:]  # 向后差分的结果
# 令最后一个时间作为最后一个用水事件的结束时间
sjJs = pd.concat([sjJs, pd.Series(True)])
# 创建数据框,并定义用水事件序列
sj = pd.DataFrame(np.arange(1, sum(sjKs)+1), columns=["事件序号"])
sj["事件起始编号"] = data.index[sjKs == 1]+1  # 定义用水事件的起始编号
sj["事件终止编号"] = data.index[sjJs == 1]+1  # 定义用水事件的终止编号
print('当阈值为4分钟的时候事件数目为:', sj.shape[0])
sj.to_csv('F:/书籍/Python数据分析与应用/df/sj.csv', index=False)

在这里插入图片描述

3、确定单次用水事件时长阈值

# 代码 9-3 确定单次用水时长
import numpy as np
import pandas as pd
data = pd.read_excel('F:/书籍/Python数据分析与应用/df/original_data.xls')
n = 4  # 使用以后四个点的平均斜率
threshold = pd.Timedelta(minutes=5) # 专家阈值
data['发生时间'] = pd.to_datetime(data['发生时间'],
    format = '%Y%m%d%H%M%S')
data = data[data['水流量'] > 0]  # 只要流量大于0的记录
# 自定义函数:输入划分时间的时间阈值,得到划分的事件数
def event_num(ts):
    d = data['发生时间'].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=['阈值'])  # 转换数据框,定义阈值列
h['事件数'] = h['阈值'].apply(event_num)  # 计算每个阈值对应的事件数
h['斜率'] = h['事件数'].diff()/0.25  # 计算每两个相邻点对应的斜率
# 往前取n个斜率绝对值平均作为斜率指标
h['斜率指标']= h['斜率'].abs().rolling(4).mean()
ts = h['阈值'][h['斜率指标'].idxmin() - n]
# 用idxmin返回最小值的Index,由于rolling_mean()计算的是前n个斜率的绝对值平均
# 所以结果要进行平移(-n)
if ts > threshold:
    ts = pd.Timedelta(minutes=4)
print('计算出的单次用水时长的阈值为:', ts)

在这里插入图片描述

9.3 构建用水行为特征并筛选用水事件

9.3.1 构建用水时长与频率特征

  不同用水事件的用水时长是基础特征之一。根据用水时长这一特征可以构建下表所示的事件开始时间、事件结束时间、洗浴时间点、用水时长、总用水时长和用水时长/总用水时长这6个特征。
在这里插入图片描述
  构建用水开始时间或结束的时间两个特征时分别减去或加上了发送阈值(发送阈值是指热水器传输数据的频率的大小)。其原因如图所示。在20:00:10时热水器记录到的数据显示还没有用水,而在 20:00:12 时,热水器记录到用水行为。所以用水开始时间在20:00:10 - 20:00:12之间考虑到网络不稳定会导致网络数据传输延时数分钟或数小时等因素。取平均值会导致很大的偏差,综合分析构建“用水开始时间”为起始数据的时间减去“发送阈值”的一半。
在这里插入图片描述
  与用水时长相关的特征只能够区分出一部分用水事件,不同用水事件的用水停顿和频率不同。例如,一次完整洗漱事件的停顿次数不多,停顿的时间长短不一,平均停顿时长较短;一次手洗衣物事件的停顿次数较多,停顿时间相差不大,平均停顿时长一般。根据这特征,可以构建表所示的停顿时长、总停顿时长、平均停顿时长和停顿次数4个特征。
在这里插入图片描述

9.3.2 构建用水量与波动特征

  除了用水时长,停顿和频率外,用水量也是识别该事件是否为洗浴事件的重要特征。例如,用水时间中的洗漱事件相比洗浴事件有 停顿次数多、用水总量少 和 平均用水少 的特点。手洗大量衣物的事件相比于洗浴事件则有 停顿次数多、用水总量多 和 平均用水量多 的特点。根据这一原因可以构建出下表所示的两个用水量特征。
在这里插入图片描述
  同时用水波动也是区分不同用水事件的关键。一般在一次洗漱事件中,刷牙和洗脸的用水量完全不同;在一次手洗衣物事件中,每次用水的量和停顿时间相差却都不大。根据不同用水事件的这一特征可以构建下表所示的水流量波动和停顿时长波动两个特征。
在这里插入图片描述

9.3.3 筛选候选洗浴事件

  洗浴事件的识别是建立在一次用水事件识别的基础上,也就是从已经划分好的一次用水事件中识别出哪些一次用水事件是洗浴事件。
  可以使用3个比较宽松的条件筛选掉那些非常短暂的用水事件,确定不可能为洗浴事件的数据去除掉,剩余的事件称为“候选洗浴事件”。这三个条件是“或”的关系,也就是说,只要一次完整的用水事件满足任意一个条件,就被判定为短暂用水事件,即会被筛选掉。3个筛选条件如下:

  • 一次用水事件中总用水量小于5升。
  • 用水时长小于100秒。
  • 总用水时长小于120秒。

经过筛选后,用水事件数目从172个减少为75个。结合日志,最终用于建模的特征的总数为11个,如下。
在这里插入图片描述

9.3.4 代码: 构建用水时长与频率特征;构建用水量与波动特征;筛选候选洗浴事件

# 代码 9-4 构建用水时长与频率特征
import pandas as pd
import numpy as np

# 读取热水器使用数据记录
data = pd.read_excel('F:/书籍/Python数据分析与应用/df/water_hearter.xlsx')
# 读取用水事件记录
sj = pd.read_csv('F:/书籍/Python数据分析与应用/df/sj.csv')
data["发生时间"] = pd.to_datetime(data["发生时间"],
                                  format="%Y%m%d%H%M%S")  # 转换时间格式
# 构造特征:总用水时长
timeDel = pd.Timedelta("0.5 sec")
sj["事件开始时间"] = data.iloc[sj["事件起始编号"] - 1, 0].values - timeDel
sj["事件结束时间"] = \
    data.iloc[sj["事件终止编号"] - 1, 0].values + timeDel
sj['洗浴时间点'] = [i.hour for i in sj["事件开始时间"]]
tmp1 = sj["事件结束时间"] - sj["事件开始时间"]
sj["总用水时长"] = np.int64(tmp1) / 1000000000 + 1
# 构造用水停顿事件
# 构造特征“停顿开始时间”、“停顿结束时间”
# 停顿开始时间指从有水流到无水流,停顿结束时间指从无水流到有水流
for i in range(len(data) - 1):
    if (data.loc[i, "水流量"] != 0) & (data.loc[i + 1, "水流量"] == 0):
        data.loc[i + 1, "停顿开始时间"] = \
            data.loc[i + 1, "发生时间"] - timeDel
    if (data.loc[i, "水流量"] == 0) & (data.loc[i + 1, "水流量"] != 0):
        data.loc[i, "停顿结束时间"] = \
            data.loc[i, "发生时间"] + timeDel
    # 提取停顿开始时间与结束时间所对应行号,放在数据框Stop中
indStopStart = data.index[data["停顿开始时间"].notnull()] + 1
indStopEnd = data.index[data["停顿结束时间"].notnull()] + 1
Stop = pd.DataFrame(data={"停顿开始编号": indStopStart[:-1],
                          "停顿结束编号": indStopEnd[1:]})
# 计算停顿时长,并放在数据框stop中,停顿时长=停顿结束时间-停顿结束时间
tmp2 = data.loc[indStopEnd[1:] - 1, "停顿结束时间"]
tmp3 = data.loc[indStopStart[:-1] - 1, "停顿开始时间"]
tmp4 = tmp2.values - tmp3.values
Stop["停顿时长"] = np.int64(tmp4) / 1000000000
# 将每次停顿与事件匹配,停顿的开始时间要大于事件的开始时间,
# 且停顿的结束时间要小于事件的结束时间
for i in range(len(sj)):
    Stop.loc[(Stop["停顿开始编号"] > sj.loc[i, "事件起始编号"]) &
             (Stop["停顿结束编号"] < sj.loc[i, "事件终止编号"]),
             "停顿归属事件"] = i + 1

# 删除停顿次数为0的事件
Stop = Stop[Stop["停顿归属事件"].notnull()]
# 构造特征 用水事件停顿总时长、停顿次数、停顿平均时长、
# 用水时长,用水/总时长
stopAgg = Stop.groupby("停顿归属事件").agg({"停顿时长": sum,
                                            "停顿开始编号": len})
sj.loc[stopAgg.index - 1, "总停顿时长"] = \
    stopAgg.loc[:, "停顿时长"].values
sj.loc[stopAgg.index - 1, "停顿次数"] = \
    stopAgg.loc[:, "停顿开始编号"].values
sj.fillna(0, inplace=True)  # 对缺失值用0插补
stopNo0 = sj["停顿次数"] != 0  # 判断用水事件是否存在停顿
sj.loc[stopNo0, "平均停顿时长"] = \
    sj.loc[stopNo0, "总停顿时长"] / sj.loc[stopNo0, "停顿次数"]
sj.fillna(0, inplace=True)  # 对缺失值用0插补
sj["用水时长"] = sj["总用水时长"] - sj["总停顿时长"]  # 定义特征用水时长
# 定义特征 用水/总时长
sj["用水/总时长"] = sj["用水时长"] / sj["总用水时长"]
print('用水事件用水时长与频率特征构造完成后数据的特征为:\n', sj.columns)
print('用水事件用水时长与频率特征构造完成后数据的前5行5列特征为:\n',
      sj.iloc[:5, :5])

# 代码 9-5 构建用水量与波动特征
data["水流量"] = data["水流量"] / 60  # 原单位L/min,现转换为L/sec
sj["总用水量"] = 0  # 给总用水量赋一个初始值0
for i in range(len(sj)):
    Start = sj.loc[i, "事件起始编号"] - 1
    End = sj.loc[i, "事件终止编号"] - 1
    if Start != End:
        for j in range(Start, End):
            if data.loc[j, "水流量"] != 0:
                sj.loc[i, "总用水量"] = (data.loc[j + 1, "发生时间"] -
                                         data.loc[j, "发生时间"]).seconds * \
                                        data.loc[j, "水流量"] + \
                                        sj.loc[i, "总用水量"]
        sj.loc[i, "总用水量"] = sj.loc[i, "总用水量"] + \
                                data.loc[End, "水流量"] * 2
    else:
        sj.loc[i, "总用水量"] = data.loc[Start, "水流量"] * 2
sj["平均水流量"] = sj["总用水量"] / sj["用水时长"]  # 定义特征 平均水流量
# 构造特征:水流量波动
# 水流量波动=∑(((单次水流的值-平均水流量)^2)*持续时间)/用水时长
sj["水流量波动"] = 0  # 给水流量波动赋一个初始值0
for i in range(len(sj)):
    Start = sj.loc[i, "事件起始编号"] - 1
    End = sj.loc[i, "事件终止编号"] - 1
    for j in range(Start, End + 1):
        if data.loc[j, "水流量"] != 0:
            slbd = (data.loc[j, "水流量"] - sj.loc[i, "平均水流量"]) ** 2
            slsj = (data.loc[j + 1, "发生时间"] -
                    data.loc[j, "发生时间"]).seconds
            sj.loc[i, "水流量波动"] = \
                slbd * slsj + sj.loc[i, "水流量波动"]
    sj.loc[i, "水流量波动"] = \
        sj.loc[i, "水流量波动"] / sj.loc[i, "用水时长"]
# 构造特征:停顿时长波动
# 停顿时长波动=∑(((单次停顿时长-平均停顿时长)^2)*持续时间)/总停顿时长
sj["停顿时长波动"] = 0  # 给停顿时长波动赋一个初始值0
for i in range(len(sj)):
    # 当停顿次数为0或1时,停顿时长波动值为0,故排除
    if sj.loc[i, "停顿次数"] > 1:
        for j in Stop.loc[Stop["停顿归属事件"] == \
                          (i + 1), "停顿时长"].values:
            sj.loc[i, "停顿时长波动"] = \
                ((j - sj.loc[i, "平均停顿时长"]) ** 2) * j + \
                sj.loc[i, "停顿时长波动"]
        sj.loc[i, "停顿时长波动"] = \
            sj.loc[i, "停顿时长波动"] / sj.loc[i, "总停顿时长"]
print('用水量和波动特征构造完成后数据的特征为:\n', sj.columns)
print('用水量和波动特征构造完成后数据的前5行5列特征为:\n',
      sj.iloc[:5, :5])

# 代码 9-6 筛选候选洗浴事件
sj_bool = (sj['用水时长'] > 100) & \
          (sj['总用水时长'] > 120) & (sj['总用水量'] > 5)
sj_final = sj.loc[sj_bool, :]
sj_final.to_excel('F:/书籍/Python数据分析与应用/df/sj_final.xlsx', index=False)
print('筛选出候选洗浴事件前的数据形状为:', sj.shape)
print('筛选出候选洗浴事件后的数据形状为:', sj_final.shape)

9.4 构建行为事件分析的BP神经网络模型

9.4.1 了解BP神经网络算法原理

  神经网络,全称人工神经网络(Artificial Neural Network,ANN),是一种模仿生物神经网络的结构和功能的数学模型或计算模型。
  以误差逆传播算法(即BP算法)而得名的BP神经网络模型(Back Propagation ANNS,简称BP网络)是神经网络中重要的网络之一。

  • 具有很强的非线性动态处理能力
  • 无须知道输入与输出之间的关系
  • 可实现高度的非线性映射

  由于其结构简单、可塑性强,在电力、交通和医疗等许多领域得到了广泛的应用。

1、原理概述

  BP神经网络由输入层、一个或多个隐藏层以及输出层构成。同层节点中没有任何耦合,每一层节点的输出只影响下一层节点的输出。网络的学习过程由正向和反向传播两部分组成。反向传播其节点单元特征通常为Sigmoid函数,如下。
S ( x ) = 1 1 + e − x S(x) = \frac{1}{1+ e^{-x}} S(x)=1+ex1
  在训练阶段用准备好的样本数据以此通过输入层、隐藏层和输出层,比较输出结果和期望值,若没有达到要求的误差程度或者训练次数,即通过输出层、隐藏层和输入层,来调节权值,以便使网络成为一定适应能力的模型。
  BP神经网络模型结构如下图所示。
在这里插入图片描述
  BP神经网络模型算法流程图
在这里插入图片描述

2、优缺点与应用领域

优点
  BP神经网络是目前应用最多的一种神经网络形式,它具备神经网络的普遍优点。有以下几个方面:

  1. 非线性映射能力。
  2. 自学习和自适应能力。
  3. 泛化能力。
  4. 容错能力。

缺点
  虽然BP网络得到了广泛的应用,但自身也存在一些缺陷和不足,主要包括以下几个方面的问题:

  1. 由于学习速率是固定的,因此网络的收敛速度慢,需要较长的训练时间。
  2. BP算法可以使权值收敛到某个值,但并不保证其为误差平面的全局最小值,这是因为采用梯度下降法可能产生一个局部最小值。
  3. 网络隐含层的层数和单元数的选择尚无理论上的指导,一般是根据经验或者通过反复实验确定。
  4. 网络的学习和记忆具有不稳定性。

应用领域
BP神经网络以其独特的结构和处理信息的方法,在许多实际应用领域中取得显著的成效,主要应用如下:
图像处理
信号处理
模式识别
机器人控制。
卫生保健,医疗
焊接领域。
经济。
此外,在电力系统、交通、军事、矿业、农业和气象等方面也有应用。

3、主要参数介绍

对于多层神经网络,scikit-learn提供了MLPClassifier类。其使用语法如下。(只展示了常用参数)

MLPClassifier(hidden_layer_sizes=(100, ), activation=’relu’, solver=’adam’, alpha=0.0001, max_iter=200, tol=0.0001, verbose=False…)

常用参数及说明如下。
在这里插入图片描述
sklearn中的模型构建训练完成后,不同的模型能够根据训练的数据输出不同的属性,MLPClassifier神经网络模型的主要属性如下表所示。
在这里插入图片描述

9.4.2 构建模型

  根据建模样本数据建立BP神经网络模型识别洗浴事件。
  由于洗浴事件与普通用水事件在特征上存在不同,而且这些不同的特征在特征上被体现出来。
  根据用户提供的用水日志,将其中洗浴事件的数据状态记录作为训练样本训练BP神经网络。然后根据训练好的网络来检验新采集到的数据,具体过程如图所示。
在这里插入图片描述

  • 在训练神经网络的时候,选取了“候选洗浴事件”的11个特征作为网络的输入,分别为:洗浴时间点,总用水时长,总停顿时长,平均停顿时长,停顿次数,用水时长,用水时长/总用水时长,总用水量,平均水流量,水流量波动和停顿时长波动。
  • 训练BP网络时给定的输出(教师信号)为1与0,其中1代表该次事件为洗浴事件,0表示该次事件不是洗浴事件。是否为洗浴事件的标签是根据热水器的用水记录日志得到。
  • 在训练BP神经网络时,对神经网络的参数进行了寻优,发现含2个隐层的神经网络训练效果较好,其中2个隐层的隐节点数分别为17和10时训练的效果较好。

  根据样本,得到训练好的神经网络后,就可以用来识别对应的用户家的洗浴事件,其中待检测的样本的11个特征作为输入,输出层输出一个值在[-1,1]范围内,如果该值小于0,则该事件不是洗浴事件,如果该值大于0,则该事件是洗浴事件。
  某热水器用户记录了两周的热水器用水日志,将前一周的数据作为训练数据,后一周的数据作为测试数据,代入上述模型进行测试。

9.4.3 评估模型

  根据该热水器用户提供的用水日志判断事件是否为洗浴与多层神经网络模型识别结果报告,如下表所示。
在这里插入图片描述
  根据模型评估报告可以看出,在洗浴事件的识别上精确率(precision)非常高,达到了96%,同时召回率(recall)也达到了70%以上。综合上述结果,可以确定此次创建的模型是有效并且效果良好的能够用于实际的洗浴事件的识别别中。

9.4.4 代码:构建并评价神经网络模型

# 代码 9-7 构建神经网络模型
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import classification_report
from sklearn.metrics import roc_curve
import matplotlib.pyplot as plt
# from sklearn.externals import joblib

# 读取数据
Xtrain = pd.read_excel('F:/书籍/Python数据分析与应用/df/sj_final.xlsx')
ytrain = pd.read_excel('F:/书籍/Python数据分析与应用/df/water_heater_log.xlsx')
test = pd.read_excel('F:/书籍/Python数据分析与应用/df/test_data.xlsx')
# 训练集测试集区分。
x_train, x_test, y_train, y_test = \
    Xtrain.iloc[:, 5:], test.iloc[:, 4:-1], \
    ytrain.iloc[:, -1], test.iloc[:, -1]
# 标准化
stdScaler = StandardScaler().fit(x_train)
x_stdtrain = stdScaler.transform(x_train)
x_stdtest = stdScaler.transform(x_test)
# 建立模型
bpnn = MLPClassifier(hidden_layer_sizes=(17, 10),
                     max_iter=200, solver='lbfgs', random_state=45)
bpnn.fit(x_stdtrain, y_train)
# 保存模型
# joblib.dump(bpnn,'water_heater_nnet.m')
print('构建的模型为:\n', bpnn)

# 代码 9-8 神经网络模型评价
# 模型预测
# bpnn = joblib.load('water_heater_nnet.m') ## 加载模型
y_pred = bpnn.predict(x_stdtest)  # 返回预测结果
print('神经网络预测结果评价报告:\n',
      classification_report(y_test, y_pred))
# 绘制roc曲线图
plt.rcParams['font.sans-serif'] = 'SimHei'  # 显示中文
plt.rcParams['axes.unicode_minus'] = False  # 显示负号
fpr, tpr, thresholds = roc_curve(y_pred, y_test)  # 求出TPR和FPR
plt.figure(figsize=(6, 4))  # 创建画布
plt.plot(fpr, tpr)  # 绘制曲线
plt.title('用户用水事件识别ROC曲线')  # 标题
plt.xlabel('FPR')  # x轴标签
plt.ylabel('TPR')  # y轴标签
# plt.savefig('用户用水事件识别ROC曲线.png')  # 保存图片
plt.show()  # 显示图形

在这里插入图片描述
在这里插入图片描述

9.5 小结

  本项目基于实时监控的智能热水器的用户使用数据,构建了BP神经网络洗浴事件识别模型,重点介绍了根据用水停顿时间间隔的阈值划分一次用水事件的过程,以及用水行为特征的构建,最后根据用户用水日志判断模型结果的好坏。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1071082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++并发与多线程(4) | 传递临时对象作为线程参数的一些问题Ⅰ

一、陷阱1 写一个传递临时对象作为线程参数的示例: #include <iostream> #include <vector> #include <thread> using namespace std;void myprint(const int& i, char* pmybuf) {cout << i << endl;cout << pmybuf << endl;r…

Python 无废话-基础知识列表list详讲

本文详细的介绍了在Python中如何处理list数据类型&#xff0c;涉及了Python 基础知识列表list 详讲&#xff0c;包含list 定义、遍历循环、元素获取、切片、添加、删除、查找元素&#xff0c;以后列表在函数、copy中使用。 列表List数据类型 列表特征 1) 列表中的各个元素&…

06. 机器学习入门2 - 理解特征和向量

文章目录 机器学习初探特征和向量机器学习的通用框架梯度下降 Hi, 你好。我是茶桁。 上一节课&#xff0c;咱们用一个案例引入了机器学习的话题&#xff0c;并跟大家讲了一下「动态规划」。 那这节课&#xff0c;我们要真正进入机器学习。 机器学习初探 在正式开始之前&…

什么是CAS机制?

CAS和Synchronized的区别是什么&#xff1f;适合什么样的场景&#xff1f;有什么样的优点和缺点&#xff1f; 示例程序&#xff1a;启动两个线程&#xff0c;每个线程中让静态变量count循环累加100次。 public class ThreadTest {private static int count 0;public static …

数据统计--图形报表--ApacheEcharts技术 --苍穹外卖day10

Apache Echarts 营业额统计 重点:已完成订单金额要排除其他状态的金额 根据时间选择区间 设计vo用于后端向前端传输数据,dto用于后端接收前端发送的数据 GetMapping("/turnoverStatistics")ApiOperation("营业额统计")public Result<TurnoverReportVO…

CamoDroid 与 Frida Android动态分析工具搭建流程(linux)

CamoDroid 与 Frida Android动态分析工具搭建流程&#xff08;linux&#xff09; 写在前面 这个东西配置起来比较复杂&#xff0c;其实最主要就是配置frida&#xff0c;如果你之前就使用过frida框架的话问题就不是很大 介绍camodroid CamoDroid 是一个开源和开放架构的 And…

图片素材免费下载,高清无水印,无需担心版权问题。

找图片素材就上这8个网站&#xff0c;免费可商用&#xff0c;建议收藏起来~ 1、菜鸟图库 https://www.sucai999.com/pic.html?vNTYwNDUx 网站主要为新手设计师提供免费素材&#xff0c;这些素材的质量都很高&#xff0c;类别也很多&#xff0c;像平面、UI、电商、视频、图片…

JVM命令行监控工具

JVM命令行监控工具 概述 性能诊断是软件工程师在日常工作中需要经常面对和解决的问题&#xff0c;在用户体验至上的今天&#xff0c;解决好应用的性能问题能带来非常大的收益。 Java作为最流行的编程语言之一&#xff0c;其应用性能诊断一直受到业界广泛关注&#xff0c;可能…

【Spring MVC研究】MVC如何浏览器请求(service方法)

文章目录 1. DispatcherServlet 的 service 方法1.1. processRequest 方法1.2. doService 方法 背景&#xff1a;平时我们学习 MVC 重点关注的时DispatcherServlet 的 doDispatcher 方法&#xff0c;但是在 doDispatcher 方法之前 还有请求处理的前置过程&#xff0c;这个过程…

B站涨粉,UP主涨粉技巧有哪些?

B 站作为深受年轻人喜爱的社交媒体平台&#xff0c;是一个不断生产优质内容的多元化文化社区&#xff0c;有不少视频出圈。随着视频行业的成熟发展&#xff0c;视频创作者们的竞争愈发激烈&#xff0c;不少创作者有涨粉难&#xff0c;曝光差的困扰。而UP主连续不断的涨粉不仅取…

CS5210芯片设计|CS5210设计方案|HDMI转VGA方案|

CS5210方案应用&#xff0c;CS5210方案设计&#xff0c;HDMI转VGA方案&#xff0c;国产集睿致远研发CS5210 HDMI到VGA转换器结合了HDMI输入接口和模拟RGB DAC输出。支持内部LDO&#xff0c;节省成本&#xff0c;优化电路板空间。CS5210适用于各种市场和显示应用程序&#xff0c…

ToBeWritten之车联网安全中常见的TOP 10漏洞

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…

MySql 终端常用指令

一、开发背景 利用数据库实现数据的增删改查 二、开发环境 Window10 mysql-8.0.33-win64 三、实现步骤 1、管理员模式打开终端 2、登录数据库&#xff08;停止 开启 登录&#xff09; 具体指令参考 MySql 安装篇 ​​​​​​​ ​​…

Redis中zSet类型的操作

一、什么是zSet zSet是一种特殊的set集合&#xff0c;它的值不能重复&#xff0c;但会对值进行排序。它有个score值&#xff0c;按照Score值从小到大进行排序。score称为分值&#xff0c;它的值是任意正浮点数。数值越小的排序越靠前。如果score相同&#xff0c;则按值的编…

NPM使用

nodejs 安装查看&#xff1a;windows11 安装Nodejs-CSDN博客 一、初始化项目 1、创建文件夹 E:\vue\projectCode\npm-demo 2、打开cmd 进入E:\vue\projectCode\npm-demo目录输入cmd 点击回车 3、先看看npm命令是否可用 npm -v 4、初始化项目 npm init package name: (npm…

动态内存管理函数(malloc,calloc,realloc,free)

动态内存函数 1.1malloc和free C语言提供了一个动态内存开辟的函数&#xff1a; void* malloc (size_t size); 这个函数向内存申请一块连续可用的空间&#xff0c;并返回指向这块空间的指针。 如果开辟成功&#xff0c;则返回一个指向开辟好空间的指针。如果开辟失败&#…

基于YOLOv8模型的120类狗狗目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的120类狗狗目标检测系统可用于日常生活中检测与定位车辆目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测算法训练数…

CMYK to RGBA

1、 算法原理 我们首先来看算法原理: 显而易见,CMYK是存储起来的四个值,通过变换可以转换成RGBA值,其中A值始终为255 2、原始代码 // The original code uses a macro UNROLL8 to unroll code and // each iteration processes eight pixels. // // The macro actually…

Spring的AOP开发-AOP简介

目录 AOP简介 AOP概念 AOP思想的实现方案 模拟AOP的基础代码 AOP相关概念 AOP简介 AOP概念 AOP&#xff0c;Aspect Oriented Programming&#xff0c;面向切面编程&#xff0c;是对面向对象编程OOP的生化&#xff0c;OOP是纵向对一个事务的抽象&#xff0c;一个对象包括静…

AIGC之下的创意革命,每个人都是文明的设计师

创意&#xff0c;人类文明的灵魂和火花。人类族群进入文明社会以来&#xff0c;创作基本由少数精英主导&#xff0c;以孔子为代表的东方教育家、哲学家提出由“学在民间”替代“学在官府”的知识传播体系也并未得到真正构建&#xff0c;作品一贯通过有限的渠道传播&#xff0c;…