1 import pandas as pd 2 import matplotlib.pyplot as plt 3 4 inputfile ='D:\original_data.xls' # 输入的数据文件 5 data = pd.read_excel(inputfile) # 读取数据 6 7 # 查看有无水流的分布 8 # 数据提取 9 lv_non = pd.value_counts(data['有无水流'])['无'] 10 lv_move = pd.value_counts(data['有无水流'])['有'] 11 # 绘制条形图 12 13 fig = plt.figure(figsize = (6 ,5)) # 设置画布大小 14 plt.rcParams['font.sans-serif'] = 'SimHei' # 设置中文显示 15 plt.rcParams['axes.unicode_minus'] = False 16 plt.bar([0,1], height=[lv_non,lv_move], width=0.4, alpha=0.8, color='skyblue') 17 plt.xticks([index for index in range(2)], ['无','有']) 18 plt.xlabel('水流状态') 19 plt.ylabel('记录数') 20 plt.title('不同水流状态记录数 num=3013',fontsize=20) 21 plt.show() 22 plt.close() 23 24 # 查看水流量分布 25 water = data['水流量'] 26 # 绘制水流量分布箱型图 27 fig = plt.figure(figsize = (5 ,8)) 28 plt.boxplot(water, 29 patch_artist=True, 30 labels = ['水流量'], # 设置x轴标题 31 boxprops = {'facecolor':'lightblue'}) # 设置填充颜色 32 plt.title('水流量分布箱线图 num=3013',fontsize=20) 33 # 显示y坐标轴的底线 34 plt.grid(axis='y') 35 plt.show()
1 # -*- coding: utf-8 -*- 2 3 # ´代码10-2 4 5 import pandas as pd 6 import numpy as np 7 data = pd.read_excel('D:\original_data.xls') 8 print('初始状态的数据形状为:', data.shape) 9 # 删除热水器编号、有无水流、节能模式属性 10 data.drop(labels=["热水器编号","有无水流","节能模式"],axis=1,inplace=True) 11 print('删除冗余属性后的数据形状为:', data.shape) 12 data.to_csv('D:\water_heart.csv',index=False) 13 14 15 # 代码10-3 16 17 # 读取数据 18 data = pd.read_csv('D:\water_heart.csv') 19 # 划分用水事件 20 threshold = pd.Timedelta('4 min') # 阈值为4分钟 21 data['发生时间'] = pd.to_datetime(data['发生时间'], format = '%Y%m%d%H%M%S') # 转换时间格式 22 data = data[data['水流量'] > 0] # 只要流量大于0的记录 23 sjKs = data['发生时间'].diff() > threshold # 相邻时间向前差分,比较是否大于阈值 24 sjKs.iloc[0] = True # 令第一个时间为第一个用水事件的开始事件 25 sjJs = sjKs.iloc[1:] # 向后差分的结果 26 sjJs = pd.concat([sjJs,pd.Series(True)]) # 令最后一个时间作为最后一个用水事件的结束时间 27 # 创建数据框,并定义用水事件序列 28 sj = pd.DataFrame(np.arange(1,sum(sjKs)+1),columns = ["事件序号"]) 29 sj["事件起始编号"] = data.index[sjKs == 1]+1 # 定义用水事件的起始编号 30 sj["事件终止编号"] = data.index[sjJs == 1]+1 # 定义用水事件的终止编号 31 print('当阈值为4分钟的时候事件数目为:',sj.shape[0]) 32 sj.to_csv('D:\sj.csv',index = False) 33 34 35 # 代码10-4 36 37 # 确定单次用水事件时长阈值 38 n = 4 # 使用以后四个点的平均斜率 39 threshold = pd.Timedelta(minutes=5) # 专家阈值 40 data['发生时间'] = pd.to_datetime(data['发生时间'], format='%Y%m%d%H%M%S') 41 data = data[data['水流量'] > 0] # 只要流量大于0的记录 42 # 自定义函数:输入划分时间的时间阈值,得到划分的事件数 43 def event_num(ts): 44 d = data['发生时间'].diff() > ts # 相邻时间作差分,比较是否大于阈值 45 return d.sum() + 1 # 这样直接返回事件数 46 dt = [pd.Timedelta(minutes=i) for i in np.arange(1, 9, 0.25)] 47 h = pd.DataFrame(dt, columns=['阈值']) # 转换数据框,定义阈值列 48 h['事件数'] = h['阈值'].apply(event_num) # 计算每个阈值对应的事件数 49 h['斜率'] = h['事件数'].diff()/0.25 # 计算每两个相邻点对应的斜率 50 h['斜率指标']= h['斜率'].abs().rolling(4).mean() # 往前取n个斜率绝对值平均作为斜率指标 51 ts = h['阈值'][h['斜率指标'].idxmin() - n] 52 # 用idxmin返回最小值的Index,由于rolling_mean()计算的是前n个斜率的绝对值平均 53 # 所以结果要进行平移(-n) 54 if ts > threshold: 55 ts = pd.Timedelta(minutes=4) 56 print('计算出的单次用水时长的阈值为:',ts) 57 58 59 60 61 # 代码10-5 62 63 data = pd.read_excel('D:\water_hearter.xls') # 读取热水器使用数据记录 64 sj = pd.read_csv('D:\sj.csv') # 读取用水事件记录 65 # 转换时间格式 66 data["发生时间"] = pd.to_datetime(data["发生时间"],format="%Y%m%d%H%M%S") 67 68 # 构造特征:总用水时长 69 timeDel = pd.Timedelta("0.5 sec") 70 sj["事件开始时间"] = data.iloc[sj["事件起始编号"]-1,0].values- timeDel 71 sj["事件结束时间"] = data.iloc[sj["事件终止编号"]-1,0].values + timeDel 72 sj['洗浴时间点'] = [i.hour for i in sj["事件开始时间"]] 73 sj["总用水时长"] = np.int64(sj["事件结束时间"] - sj["事件开始时间"])/1000000000 + 1 74 75 # 构造用水停顿事件 76 # 构造特征“停顿开始时间”、“停顿结束时间” 77 # 停顿开始时间指从有水流到无水流,停顿结束时间指从无水流到有水流 78 for i in range(len(data)-1): 79 if (data.loc[i,"水流量"] != 0) & (data.loc[i + 1,"水流量"] == 0) : 80 data.loc[i + 1,"停顿开始时间"] = data.loc[i +1, "发生时间"] - timeDel 81 if (data.loc[i,"水流量"] == 0) & (data.loc[i + 1,"水流量"] != 0) : 82 data.loc[i,"停顿结束时间"] = data.loc[i , "发生时间"] + timeDel 83 84 # 提取停顿开始时间与结束时间所对应行号,放在数据框Stop中 85 indStopStart = data.index[data["停顿开始时间"].notnull()]+1 86 indStopEnd = data.index[data["停顿结束时间"].notnull()]+1 87 Stop = pd.DataFrame(data={"停顿开始编号":indStopStart[:-1], 88 "停顿结束编号":indStopEnd[1:]}) 89 # 计算停顿时长,并放在数据框stop中,停顿时长=停顿结束时间-停顿结束时间 90 Stop["停顿时长"] = np.int64(data.loc[indStopEnd[1:]-1,"停顿结束时间"].values- 91 data.loc[indStopStart[:-1]-1,"停顿开始时间"].values)/1000000000 92 # 将每次停顿与事件匹配,停顿的开始时间要大于事件的开始时间, 93 # 且停顿的结束时间要小于事件的结束时间 94 for i in range(len(sj)): 95 Stop.loc[(Stop["停顿开始编号"] > sj.loc[i,"事件起始编号"]) & 96 (Stop["停顿结束编号"] < sj.loc[i,"事件终止编号"]),"停顿归属事件"]=i+1 97 98 # 删除停顿次数为0的事件 99 Stop = Stop[Stop["停顿归属事件"].notnull()] 100 101 # 构造特征 用水事件停顿总时长、停顿次数、停顿平均时长、 102 # 用水时长,用水/总时长 103 stopAgg = Stop.groupby("停顿归属事件").agg({"停顿时长":sum,"停顿开始编号":len}) 104 sj.loc[stopAgg.index - 1,"总停顿时长"] = stopAgg.loc[:,"停顿时长"].values 105 sj.loc[stopAgg.index-1,"停顿次数"] = stopAgg.loc[:,"停顿开始编号"].values 106 sj.fillna(0,inplace=True) # 对缺失值用0插补 107 stopNo0 = sj["停顿次数"] != 0 # 判断用水事件是否存在停顿 108 sj.loc[stopNo0,"平均停顿时长"] = sj.loc[stopNo0,"总停顿时长"]/sj.loc[stopNo0,"停顿次数"] 109 sj.fillna(0,inplace=True) # 对缺失值用0插补 110 sj["用水时长"] = sj["总用水时长"] - sj["总停顿时长"] # 定义特征用水时长 111 sj["用水/总时长"] = sj["用水时长"] / sj["总用水时长"] # 定义特征 用水/总时长 112 print('用水事件用水时长与频率特征构造完成后数据的特征为:\n',sj.columns) 113 print('用水事件用水时长与频率特征构造完成后数据的前5行5列特征为:\n', 114 sj.iloc[:5,:5]) 115 116 117 118 # ´代码10-6 119 120 data["水流量"] = data["水流量"] / 60 # 原单位L/min,现转换为L/sec 121 sj["总用水量"] = 0 # 给总用水量赋一个初始值0 122 for i in range(len(sj)): 123 Start = sj.loc[i,"事件起始编号"]-1 124 End = sj.loc[i,"事件终止编号"]-1 125 if Start != End: 126 for j in range(Start,End): 127 if data.loc[j,"水流量"] != 0: 128 sj.loc[i,"总用水量"] = (data.loc[j + 1,"发生时间"] - 129 data.loc[j,"发生时间"]).seconds* \ 130 data.loc[j,"水流量"] + sj.loc[i,"总用水量"] 131 sj.loc[i,"总用水量"] = sj.loc[i,"总用水量"] + data.loc[End,"水流量"] * 2 132 else: 133 sj.loc[i,"总用水量"] = data.loc[Start,"水流量"] * 2 134 135 sj["平均水流量"] = sj["总用水量"] / sj["用水时长"] # 定义特征 平均水流量 136 # 构造特征:水流量波动 137 # 水流量波动=∑(((单次水流的值-平均水流量)^2)*持续时间)/用水时长 138 sj["水流量波动"] = 0 # 给水流量波动赋一个初始值0 139 for i in range(len(sj)): 140 Start = sj.loc[i,"事件起始编号"] - 1 141 End = sj.loc[i,"事件终止编号"] - 1 142 for j in range(Start,End + 1): 143 if data.loc[j,"水流量"] != 0: 144 slbd = (data.loc[j,"水流量"] - sj.loc[i,"平均水流量"])**2 145 slsj = (data.loc[j + 1,"发生时间"] - data.loc[j,"发生时间"]).seconds 146 sj.loc[i,"水流量波动"] = slbd * slsj + sj.loc[i,"水流量波动"] 147 sj.loc[i,"水流量波动"] = sj.loc[i,"水流量波动"] / sj.loc[i,"用水时长"] 148 149 # 构造特征:停顿时长波动 150 # 停顿时长波动=∑(((单次停顿时长-平均停顿时长)^2)*持续时间)/总停顿时长 151 sj["停顿时长波动"] = 0 # 给停顿时长波动赋一个初始值0 152 for i in range(len(sj)): 153 if sj.loc[i,"停顿次数"] > 1: # 当停顿次数为0或1时,停顿时长波动值为0,故排除 154 for j in Stop.loc[Stop["停顿归属事件"] == (i+1),"停顿时长"].values: 155 sj.loc[i,"停顿时长波动"] = ((j - sj.loc[i,"平均停顿时长"])**2) * j + \ 156 sj.loc[i,"停顿时长波动"] 157 sj.loc[i,"停顿时长波动"] = sj.loc[i,"停顿时长波动"] / sj.loc[i,"总停顿时长"] 158 159 print('用水量和波动特征构造完成后数据的特征为:\n',sj.columns) 160 print('用水量和波动特征构造完成后数据的前5行5列特征为:\n',sj.iloc[:5,:5]) 161 162 163 164 165 # 代码10-7 166 167 sj_bool = (sj['用水时长'] >100) & (sj['总用水时长'] > 120) & (sj['总用水量'] > 5) 168 sj_final = sj.loc[sj_bool,:] 169 sj_final.to_csv('D:\sj_final.csv',index=False) 170 print('筛选出候选洗浴事件前的数据形状为:',sj.shape) 171 print('筛选出候选洗浴事件后的数据形状为:',sj_final.shape)
1 # -*- coding: utf-8 -*- 2 3 # 代码10-8 4 5 import pandas as pd 6 from sklearn.preprocessing import StandardScaler 7 from sklearn.neural_network import MLPClassifier 8 import joblib 9 10 # 读取数据 11 Xtrain = pd.read_csv('D:\sj_final.csv') 12 ytrain = pd.read_excel('D:\water_heater_log.xlsx') 13 test = pd.read_excel('D:\\test_data.xlsx') 14 # 训练集测试集区分。 15 x_train, x_test, y_train, y_test = Xtrain.iloc[:,5:],test.iloc[:,4:-1],\ 16 ytrain.iloc[:,-1],test.iloc[:,-1] 17 # 标准化 18 stdScaler = StandardScaler().fit(x_train) 19 x_stdtrain = stdScaler.transform(x_train) 20 x_stdtest = stdScaler.transform(x_test) 21 # 建立模型 22 bpnn = MLPClassifier(hidden_layer_sizes = (17,10), max_iter = 200, solver = 'lbfgs',random_state=50) 23 bpnn.fit(x_stdtrain, y_train) 24 # 保存模型 25 joblib.dump(bpnn,'D:\water_heater_nnet.m') 26 print('构建的模型为:\n',bpnn) 27 28 29 # -*- coding: utf-8 -*- 30 31 # 代码10-9 32 33 # 模型评价 34 from sklearn.metrics import classification_report 35 from sklearn.metrics import roc_curve 36 import joblib 37 import matplotlib.pyplot as plt 38 39 bpnn = joblib.load('D:\water_heater_nnet.m') # 加载模型 40 y_pred = bpnn.predict(x_stdtest) # 返回预测结果 41 print('神经网络预测结果评价报告:\n',classification_report(y_test,y_pred)) 42 # 绘制roc曲线图 43 plt.rcParams['font.sans-serif'] = 'SimHei' # 显示中文 44 plt.rcParams['axes.unicode_minus'] = False # 显示负号 45 fpr, tpr, thresholds = roc_curve(y_pred,y_test) # 求出TPR和FPR 46 plt.figure(figsize=(6,4)) # 创建画布 47 plt.plot(fpr,tpr) # 绘制曲线 48 plt.title('用户用水事件识别ROC曲线 num=3013',fontsize=20) # 标题 49 plt.xlabel('FPR') # x轴标签 50 plt.ylabel('TPR') # y轴标签 51 plt.savefig('D:\用户用水事件识别ROC曲线.png') # 保存图片 52 plt.show() # 显示图形