python大数据:实战热水器用户行为识别(二、数据预处理)

四、数据预处理

1. 属性归约

因为分析主要对象热水器用户,分析的主要目的为热水器用户洗浴行为的一般规律,所以“热水器编号”属性可以除去;因为“有无水流”可以通过“水流量”属性反映出来,“节能模式”属性取值相同均为“关”,对分析无用,可以去除。

删除“热水器编号”、“有无水流”、“节能模式”后数据如下所示:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline


data = pd.read_excel('../data/original_data.xls')
print('初始状态的数据形状为:', data.shape)
# 删除热水器编号、有无水流、节能模式属性
data.drop(labels=["热水器编号","有无水流","节能模式"],axis=1,inplace=True) 
print('删除冗余属性后的数据形状为:', data.shape)
data.to_csv('../tmp/water_heart.csv',index=False)
初始状态的数据形状为: (18840, 12)
删除冗余属性后的数据形状为: (18840, 9)

2. 划分用水事件

在用水状态记录中水流量不为0,表明热水器用户正在使用热水;而水流量为0时,表明热水器用户用热水时发生了停顿或者用热水结束。对于任何一个用水记录,如果它的向前时差超过了阈值T,则将它记为事件的开始编号;如果它的向后时差超过阈值T,则将其记为时间的结束编号。划分模型的符号说明如下表所示。

符号释义
t 1 t_1 t1所有水流量不为0的用水行为的发生时间
时间间隔阈值 T T T
data = pd.read_csv('../tmp/water_heart.csv')
# 划分用水事件
threshold = pd.Timedelta('1 min')  # 阈值为4分钟
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('../tmp/sj.csv',index = False)
当阈值为4分钟的时候事件数目为: 232

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

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)]
x = np.arange(1, 9, 0.25)
h = pd.DataFrame(dt, columns=['阈值'])  # 转换数据框,定义阈值列
h['事件数'] = h['阈值'].apply(event_num)  # 计算每个阈值对应的事件数
h['斜率'] = h['事件数'].diff()/0.25  # 计算每两个相邻点对应的斜率
h['斜率指标']= h['斜率'].abs().rolling(4).mean()  # 往前取n个斜率绝对值平均作为斜率指标
h['x'] = x
ts = h['阈值'][h['斜率指标'].idxmin() - n]
# 用idxmin返回最小值的Index,由于rolling_mean()计算的是前n个斜率的绝对值平均
# 所以结果要进行平移(-n)
if ts > threshold:
    ts = pd.Timedelta(minutes=4)
print('计算出的单次用水时长的阈值为:',ts)

plt.rcParams['font.sans-serif'] = 'SimHei'  # 设置中文显示
plt.rcParams['axes.unicode_minus'] = False
# h['事件数'].plot(label = u'事件数', legend = True)
plt.plot(h['x'], h['事件数'])
计算出的单次用水时长的阈值为: 0 days 00:04:00

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EI8DaTjc-1579681968793)(output_5_2.png)]

4. 属性构造

(1)构建用水时长与频率属性

data = pd.read_excel('../data/water_hearter.xlsx',encoding='gbk')  # 读取热水器使用数据记录
sj = pd.read_csv('../tmp/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["事件开始时间"]]

### 这里总用水时长感觉不用加1!!!!
sj["总用水时长"] = np.int64(sj["事件结束时间"] - sj["事件开始时间"])/1000000000 + 1

sj.head(10)
事件序号事件起始编号事件终止编号事件开始时间事件结束时间洗浴时间点总用水时长
01332014-10-19 07:01:55.5002014-10-19 07:01:56.50072.0
1257572014-10-19 07:38:15.5002014-10-19 07:38:16.50072.0
233823852014-10-19 09:46:37.5002014-10-19 09:47:15.500939.0
344054052014-10-19 11:50:16.5002014-10-19 11:50:17.500112.0
454084082014-10-19 13:56:20.5002014-10-19 13:56:21.500132.0
564115942014-10-19 15:34:38.5002014-10-19 15:48:46.50015849.0
676136192014-10-19 15:55:14.5002014-10-19 15:55:29.5001516.0
786606662014-10-19 17:23:20.5002014-10-19 17:23:41.5001722.0
896687632014-10-19 17:24:57.5002014-10-19 17:31:32.50017396.0
9107667662014-10-19 17:34:35.5002014-10-19 17:34:36.500172.0
# 构造用水停顿事件
# 构造特征“停顿开始时间”、“停顿结束时间”
# 停顿开始时间指从有水流到无水流,停顿结束时间指从无水流到有水流
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
data.head(10)
发生时间开关机状态加热中保温中实际温度热水量水流量加热剩余时间当前设置温度停顿结束时间停顿开始时间
02014-10-19 06:39:1730°C0%00分钟50°CNaTNaT
12014-10-19 07:01:5430°C0%00分钟50°C2014-10-19 07:01:54.500NaT
22014-10-19 07:01:5630°C0%80分钟50°CNaTNaT
32014-10-19 07:12:3030°C0%00分钟50°CNaT2014-10-19 07:12:29.500
42014-10-19 07:12:3629°C0%00分钟50°CNaTNaT
52014-10-19 07:16:0230°C0%00分钟50°CNaTNaT
62014-10-19 07:16:0829°C0%00分钟50°CNaTNaT
72014-10-19 07:20:0530°C0%00分钟50°CNaTNaT
82014-10-19 07:20:1029°C0%00分钟50°CNaTNaT
92014-10-19 07:21:5330°C0%00分钟50°CNaTNaT
# 提取停顿开始时间与结束时间所对应行号,放在数据框Stop中
indStopStart = data.index[data["停顿开始时间"].notnull()]+1
indStopEnd = data.index[data["停顿结束时间"].notnull()]+1
Stop = pd.DataFrame(data={"停顿开始编号":indStopStart[:-1],
                            "停顿结束编号":indStopEnd[1:]}) 
# 计算停顿时长,并放在数据框stop中,停顿时长=停顿结束时间-停顿结束时间
Stop["停顿时长"] = np.int64(data.loc[indStopEnd[1:]-1,"停顿结束时间"].values-
                     data.loc[indStopStart[:-1]-1,"停顿开始时间"].values)/1000000000
Stop.head(10)
停顿开始编号停顿结束编号停顿时长
04561545.0
1583817682.0
23843841.0
33864042130.0
44064071679.0
54094105007.0
645345411.0
7595612286.0
86206595259.0
96676671.0
# 将每次停顿与事件匹配,停顿的开始时间要大于事件的开始时间,
# 且停顿的结束时间要小于事件的结束时间
for i in range(len(sj)):
    Stop.loc[(Stop["停顿开始编号"] > sj.loc[i,"事件起始编号"]) & 
           (Stop["停顿结束编号"] < sj.loc[i,"事件终止编号"]),"停顿归属事件"]=i+1

# 删除停顿次数为0的事件
Stop = Stop[Stop["停顿归属事件"].notnull()]
Stop.head(10)
停顿开始编号停顿结束编号停顿时长停顿归属事件
23843841.03.0
645345411.06.0
16114311431.015.0
20135013501.018.0
21135313531.018.0
23136813681.019.0
24137113711.019.0
25137713771.019.0
32157815781.025.0
41216621661.033.0
# 构造特征 用水事件停顿总时长、停顿次数、停顿平均时长、
# 用水时长,用水/总时长
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])
sj.head(10)
用水事件用水时长与频率特征构造完成后数据的特征为:
 Index(['事件序号', '事件起始编号', '事件终止编号', '事件开始时间', '事件结束时间', '洗浴时间点', '总用水时长',
       '总停顿时长', '停顿次数', '平均停顿时长', '用水时长', '用水/总时长'],
      dtype='object')
用水事件用水时长与频率特征构造完成后数据的前5行5列特征为:
    事件序号  事件起始编号  事件终止编号                  事件开始时间                  事件结束时间
0     1       3       3 2014-10-19 07:01:55.500 2014-10-19 07:01:56.500
1     2      57      57 2014-10-19 07:38:15.500 2014-10-19 07:38:16.500
2     3     382     385 2014-10-19 09:46:37.500 2014-10-19 09:47:15.500
3     4     405     405 2014-10-19 11:50:16.500 2014-10-19 11:50:17.500
4     5     408     408 2014-10-19 13:56:20.500 2014-10-19 13:56:21.500
事件序号事件起始编号事件终止编号事件开始时间事件结束时间洗浴时间点总用水时长总停顿时长停顿次数平均停顿时长用水时长用水/总时长
01332014-10-19 07:01:55.5002014-10-19 07:01:56.50072.00.00.00.02.01.000000
1257572014-10-19 07:38:15.5002014-10-19 07:38:16.50072.00.00.00.02.01.000000
233823852014-10-19 09:46:37.5002014-10-19 09:47:15.500939.01.01.01.038.00.974359
344054052014-10-19 11:50:16.5002014-10-19 11:50:17.500112.00.00.00.02.01.000000
454084082014-10-19 13:56:20.5002014-10-19 13:56:21.500132.00.00.00.02.01.000000
564115942014-10-19 15:34:38.5002014-10-19 15:48:46.50015849.011.01.011.0838.00.987044
676136192014-10-19 15:55:14.5002014-10-19 15:55:29.5001516.00.00.00.016.01.000000
786606662014-10-19 17:23:20.5002014-10-19 17:23:41.5001722.00.00.00.022.01.000000
896687632014-10-19 17:24:57.5002014-10-19 17:31:32.50017396.00.00.00.0396.01.000000
9107667662014-10-19 17:34:35.5002014-10-19 17:34:36.500172.00.00.00.02.01.000000
**2)构建用水量与波动属性**
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 ## 默认单次事件时长为2秒
        
sj["平均水流量"] = sj["总用水量"] / sj["用水时长"] # 定义特征 平均水流量
sj.head(10)
事件序号事件起始编号事件终止编号事件开始时间事件结束时间洗浴时间点总用水时长总停顿时长停顿次数平均停顿时长用水时长用水/总时长总用水量平均水流量
01332014-10-19 07:01:55.5002014-10-19 07:01:56.50072.00.00.00.02.01.0000000.0044440.002222
1257572014-10-19 07:38:15.5002014-10-19 07:38:16.50072.00.00.00.02.01.0000000.0044440.002222
233823852014-10-19 09:46:37.5002014-10-19 09:47:15.500939.01.01.01.038.00.9743590.0850000.002237
344054052014-10-19 11:50:16.5002014-10-19 11:50:17.500112.00.00.00.02.01.0000000.0122220.006111
454084082014-10-19 13:56:20.5002014-10-19 13:56:21.500132.00.00.00.02.01.0000000.0044440.002222
564115942014-10-19 15:34:38.5002014-10-19 15:48:46.50015849.011.01.011.0838.00.9870449.4158330.011236
676136192014-10-19 15:55:14.5002014-10-19 15:55:29.5001516.00.00.00.016.01.0000000.2422220.015139
786606662014-10-19 17:23:20.5002014-10-19 17:23:41.5001722.00.00.00.022.01.0000000.3794440.017247
896687632014-10-19 17:24:57.5002014-10-19 17:31:32.50017396.00.00.00.0396.01.0000002.8991670.007321
9107667662014-10-19 17:34:35.5002014-10-19 17:34:36.500172.00.00.00.02.01.0000000.0044440.002222
# 构造特征:水流量波动
# 水流量波动=∑(((单次水流的值-平均水流量)^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,"用水时长"] 
sj.head(10)
事件序号事件起始编号事件终止编号事件开始时间事件结束时间洗浴时间点总用水时长总停顿时长停顿次数平均停顿时长用水时长用水/总时长总用水量平均水流量水流量波动
01332014-10-19 07:01:55.5002014-10-19 07:01:56.50072.00.00.00.02.01.0000000.0044440.0022220.000000e+00
1257572014-10-19 07:38:15.5002014-10-19 07:38:16.50072.00.00.00.02.01.0000000.0044440.0022220.000000e+00
233823852014-10-19 09:46:37.5002014-10-19 09:47:15.500939.01.01.01.038.00.9743590.0850000.0022371.522223e-03
344054052014-10-19 11:50:16.5002014-10-19 11:50:17.500112.00.00.00.02.01.0000000.0122220.0061110.000000e+00
454084082014-10-19 13:56:20.5002014-10-19 13:56:21.500132.00.00.00.02.01.0000000.0044440.0022220.000000e+00
564115942014-10-19 15:34:38.5002014-10-19 15:48:46.50015849.011.01.011.0838.00.9870449.4158330.0112364.975237e-06
676136192014-10-19 15:55:14.5002014-10-19 15:55:29.5001516.00.00.00.016.01.0000000.2422220.0151391.681375e-05
786606662014-10-19 17:23:20.5002014-10-19 17:23:41.5001722.00.00.00.022.01.0000000.3794440.0172472.600616e-07
896687632014-10-19 17:24:57.5002014-10-19 17:31:32.50017396.00.00.00.0396.01.0000002.8991670.0073214.286956e-06
9107667662014-10-19 17:34:35.5002014-10-19 17:34:36.500172.00.00.00.02.01.0000000.0044440.0022220.000000e+00
# 构造特征:停顿时长波动
# 停顿时长波动=∑(((单次停顿时长-平均停顿时长)^2)*持续时间)/总停顿时长
sj["停顿时长波动"] = 0 # 给停顿时长波动赋一个初始值0
for i in range(len(sj)):
    if sj.loc[i,"停顿次数"] > 1: # 当停顿次数为0或1时,停顿时长波动值为0,故排除
        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])
sj.head(10)
用水量和波动特征构造完成后数据的特征为:
 Index(['事件序号', '事件起始编号', '事件终止编号', '事件开始时间', '事件结束时间', '洗浴时间点', '总用水时长',
       '总停顿时长', '停顿次数', '平均停顿时长', '用水时长', '用水/总时长', '总用水量', '平均水流量', '水流量波动',
       '停顿时长波动'],
      dtype='object')
用水量和波动特征构造完成后数据的前5行5列特征为:
    事件序号  事件起始编号  事件终止编号                  事件开始时间                  事件结束时间
0     1       3       3 2014-10-19 07:01:55.500 2014-10-19 07:01:56.500
1     2      57      57 2014-10-19 07:38:15.500 2014-10-19 07:38:16.500
2     3     382     385 2014-10-19 09:46:37.500 2014-10-19 09:47:15.500
3     4     405     405 2014-10-19 11:50:16.500 2014-10-19 11:50:17.500
4     5     408     408 2014-10-19 13:56:20.500 2014-10-19 13:56:21.500
事件序号事件起始编号事件终止编号事件开始时间事件结束时间洗浴时间点总用水时长总停顿时长停顿次数平均停顿时长用水时长用水/总时长总用水量平均水流量水流量波动停顿时长波动
01332014-10-19 07:01:55.5002014-10-19 07:01:56.50072.00.00.00.02.01.0000000.0044440.0022220.000000e+000.0
1257572014-10-19 07:38:15.5002014-10-19 07:38:16.50072.00.00.00.02.01.0000000.0044440.0022220.000000e+000.0
233823852014-10-19 09:46:37.5002014-10-19 09:47:15.500939.01.01.01.038.00.9743590.0850000.0022371.522223e-030.0
344054052014-10-19 11:50:16.5002014-10-19 11:50:17.500112.00.00.00.02.01.0000000.0122220.0061110.000000e+000.0
454084082014-10-19 13:56:20.5002014-10-19 13:56:21.500132.00.00.00.02.01.0000000.0044440.0022220.000000e+000.0
564115942014-10-19 15:34:38.5002014-10-19 15:48:46.50015849.011.01.011.0838.00.9870449.4158330.0112364.975237e-060.0
676136192014-10-19 15:55:14.5002014-10-19 15:55:29.5001516.00.00.00.016.01.0000000.2422220.0151391.681375e-050.0
786606662014-10-19 17:23:20.5002014-10-19 17:23:41.5001722.00.00.00.022.01.0000000.3794440.0172472.600616e-070.0
896687632014-10-19 17:24:57.5002014-10-19 17:31:32.50017396.00.00.00.0396.01.0000002.8991670.0073214.286956e-060.0
9107667662014-10-19 17:34:35.5002014-10-19 17:34:36.500172.00.00.00.02.01.0000000.0044440.0022220.000000e+000.0
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Python大数据实战项目是指使用Python语言进行大数据处理和分析的项目。这种项目通常涉及到使用Python的相关库和工具,如Pandas、Numpy、Matplotlib等,来处理和分析大规模的数据。在这样的项目中,可以使用Python来进行数据清洗、数据预处理、数据挖掘、机器学习和可视化等任务。 引用中提到了一个基于Python实现的整个项目分析的流程,包括数据预处理、数据可视化、数据挖掘和数据建模等步骤。这个项目还使用了自定义的LRFMP模型来进行用户画像分析,并以词云的形式展示出来。 引用中提到了十大Python经典就业练手项目,这些项目贴合企业的用人标准,可以帮助想入坑Python或者正在学习Python的人们提升就业竞争力。 引用中指出了Python的流行原因之一是它简单易学,吸引了大量程序员的关注和学习。在Python的就业方向中,大数据领域是一个重要的方向之一。Python可以用于大数据分析、数据挖掘和机器学习等任务,在这些项目中处理和分析大规模的数据。 引用中提到了一些大数据实战项目的练习目标,包括数据分析和数据挖掘、Jupyter notebook的使用、Numpy矩阵和随机数生成、Pandas的数据结构和操作、数据的可视化等。 因此,大数据实战项目是指使用Python进行大规模数据处理和分析的项目,可以涉及数据预处理、数据挖掘、机器学习和可视化等任务。这些项目可以帮助人们提升Python编程能力,并在大数据领域中找到就业机会。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值