当前位置:   article > 正文

python深度学习--jena温度预测_使用cnn进行温度预测

使用cnn进行温度预测
  1. import numpy as np
  2. import pandas as pd
  3. import matplotlib.pyplot as plt
  4. import pylab
  5. from pandas import DataFrame, Series
  6. from keras import models, layers, optimizers, losses, metrics
  7. from keras.utils.np_utils import to_categorical
  8. import os
  9. #遇到新问题时,最好首先为你选择的指标建立一个基于常识的基准。 如果没有需要打败的基准,那么就无法分辨是否取得了真正的进步
  10. fname='F:/jena_climate_2009_2016.csv'#jena天气数据集(2009—2016 年的数据,每 10 分钟记录 14 个不同的量)
  11. def fread(fname):
  12. f=open(fname)
  13. data=f.read()
  14. f.close()
  15. lines=data.split('\n')
  16. header=lines[0].split(',')
  17. lines=lines[1:]
  18. return header,lines
  19. #对于.csv数据格式等用pandas操作更加方便
  20. df=pd.read_csv(fname,)
  21. temperature=df['T (degC)']
  22. # print(temperature)
  23. pre_10=df.ix[:1440,2]
  24. #绘制温度时间序列
  25. # fig=plt.figure()
  26. # ax1=fig.add_subplot(2,1,1)
  27. # ax2=fig.add_subplot(2,1,2)
  28. # temperature.plot(ax=ax1)
  29. # pre_10.plot(ax=ax2)
  30. # plt.show()
  31. #一个时间步是 10 分钟,每 steps 个时间步采样一次数据,给定过去 lookback 个时间步之内的数据,能否预测 delay 个时间步之后的温度?
  32. # lookback=720-----#过去5天内的观测数据
  33. # steps=6---------#观测数据的采样频率是每小时一个数据点。
  34. # delay=144---------#目标是未来 24 小时之后的数据
  35. #准备数据
  36. #数据类型不同,所以需要标准化
  37. #预处理数据的方法是,将每个时间序列减去其平均值,然后除以其标准差
  38. df=df.drop(['Date Time'],axis=1)
  39. float_data=df.ix[:,:]
  40. # print(train_data)
  41. mean=float_data.mean(axis=0)
  42. # print(mean)
  43. float_data-=mean
  44. std=float_data.std(axis=0)
  45. float_data /=std
  46. # print(float_data)
  47. #生成时间序列样本及其目标的生成器
  48. '''
  49. data:浮点数数据组成的原始数组,标准化后的数据。
  50. lookback:输入数据应该包括过去多少个时间步。一个时间步是 10 分钟
  51. delay:目标应该在未来多少个时间步之后。
  52. min_index 和 max_index:data 数组中的索引,用于界定需要抽取哪些时间步。这有助于保存一部分数据用于验证、另一部分用于测试。
  53. shuffle:是否打乱样本。
  54. batch_size:每个批量的样本数。
  55. step:数据采样的周期(单位:时间步)。我们将其设为6,为的是每小时抽取一个数据点
  56. '''
  57. def generator(data,lookback,delay,min_index,max_index,shuffle=False,batch_size=128,step=6):
  58. if max_index is None:
  59. max_index=len(data)-delay-1
  60. #[0--min_index--lookback--max_index--delay--len(data)]
  61. # i
  62. i=min_index+lookback
  63. while 1:
  64. if shuffle:
  65. rows=np.random.randint(min_index+lookback,max_index,size=batch_size)
  66. else:
  67. if i+batch_size>=max_index:#表明取到最后一批(数量<batch_size)
  68. i=min_index+lookback
  69. rows=np.arange(i,min(i+batch_size,max_index))
  70. i+=len(rows)
  71. samples=np.zeros((len(rows),lookback//step,data.shape[-1]))#按小时批量抽取数据点,每个点包含14个特征
  72. # print(samples)
  73. targets=np.zeros((len(rows),))
  74. for j,row in enumerate(rows):
  75. indices=range(rows[j]-lookback,rows[j],step)#6步(每小时)一个点索引
  76. samples[j]=data.ix[indices,:]
  77. t=data.ix[rows[j]+delay,:]
  78. targets[j]=t[1]#144步(24小时后的温度数组)
  79. yield samples,targets
  80. #准备训练生成器、验证生成器和测试生成器
  81. lookback=1440
  82. step=6
  83. delay=144
  84. batch_size=128
  85. train_gen=generator(
  86. float_data,
  87. lookback=lookback,
  88. delay=delay,
  89. min_index=0,
  90. max_index=200000,
  91. shuffle=True,
  92. step=step,
  93. batch_size=batch_size)
  94. val_gen=generator(
  95. float_data,
  96. lookback=lookback,
  97. delay=delay,
  98. min_index=200001,
  99. max_index=300000,
  100. shuffle=True,
  101. step=step,
  102. batch_size=batch_size)
  103. test_gen=generator(
  104. float_data,
  105. lookback=lookback,
  106. delay=delay,
  107. min_index=300001,
  108. max_index=None,
  109. step=step,
  110. batch_size=batch_size)
  111. val_steps = (300000 - 200001 - lookback) //batch_size
  112. print(val_steps)
  113. test_steps = (len(float_data) - 300001 - lookback) //batch_size
  114. #一种基于常识的、非机器学习的基准方法
  115. '''
  116. #为合理性检查,还可以建立一个基准,更高级的机器学习模型需要打败这个基准才能表现出其有效性.比如,如果数据集中包含 90% 的类别A实例和 10% 的类别 B
  117. 实例,那么分类任务的一种基于常识的方法就是对新样本 始终预测类别“A”。这种分类器的总体精度为 90%,因此任何基于学习的方法在精度高于90%时才能证明其有效性
  118. #这里,温度随时间序列是连续的,并且具有每天的周期性变化。因此,一种基于常识的方法就是始终预测 24 小时后的温度等于现在的温度。我们使用平均绝对误差(MAE)指标来评估这种方法
  119. '''
  120. #np.mean(np.abs(preds-targets))
  121. #计算符合常识的基准方法的MAE
  122. def evaluate_naive_method():
  123. batch_maes=[]
  124. for step in range(val_steps):#每次批处理的mae
  125. samples, targets = next(val_gen)#类似于i+=1,处理完当前批,指向下一批
  126. preds=samples[:,-1,1]#预测值等于当前值
  127. mae=np.mean(np.abs(preds-targets))
  128. batch_maes.append(mae)
  129. print(np.mean(batch_maes))#0.30355672736802614
  130. return np.mean(batch_maes)
  131. # t=evaluate_naive_method()
  132. # celsius_mae = t * std[1]
  133. # print(celsius_mae)#2.5569691766905067≈2.56℃平均绝对误差还是相当大的
  134. #一种基本的机器学习基准方法
  135. '''
  136. 在开始研究 复杂且计算代价很高的模型(比如RNN)之前,尝试使用简单且计算代价低的机器学习模型也 是很有用的,比如小型的密集连接网络。这可以保证进一步增加问题的复杂度是合理的,并且会带来真正的好处
  137. '''
  138. #训练并评估一个密集连接模型
  139. from keras.models import Sequential
  140. from keras import layers
  141. from keras.optimizers import RMSprop
  142. def build_DENSE():
  143. model = Sequential()
  144. model.add(layers.Flatten(input_shape=(lookback // step, float_data.shape[-1])))
  145. model.add(layers.Dense(32, activation='relu'))
  146. model.add(layers.Dense(1))
  147. model.compile(optimizer=RMSprop(), loss='mae')
  148. history = model.fit_generator(
  149. train_gen,
  150. steps_per_epoch=500,
  151. epochs=20,
  152. validation_data=val_gen,
  153. validation_steps=val_steps)
  154. return history
  155. def acc_loss_plot(history):
  156. fig=plt.figure()
  157. ax1=fig.add_subplot(2,1,1)
  158. # acc = history.history['acc']
  159. # val_acc = history.history['val_acc']
  160. loss = history.history['loss']
  161. val_loss = history.history['val_loss']
  162. epochs = range(1, len(loss) + 1)
  163. # ax1.plot(epochs, acc, 'bo', label='Training acc')
  164. # ax1.plot(epochs, val_acc, 'b', label='Validation acc')
  165. ax1.set_title('Training and validation accuracy')
  166. ax2=fig.add_subplot(2,1,2)
  167. ax2.plot(epochs, loss, 'bo', label='Training loss')
  168. ax2.plot(epochs, val_loss, 'b', label='Validation loss')
  169. ax2.set_title('Training and validation loss')
  170. plt.legend()
  171. plt.tight_layout()
  172. plt.show()
  173. # acc_loss_plot(build_DENSE())#除了开始意外,验证损失最低0.32>非学习基准方法
  174. '''
  175. 事实证明,超越这个基准并不容易。我们的常识中包含了大量有价值的信息, 而机器学习模型并不知道这些信息.
  176. 如果你在一个复杂模型的空间中寻找解决方案,那么可能无法学到简单且性能良好的基准方法
  177. 机器学习的一个非常重要的限制:
  178. 如果学习算法没有被硬编码要求去寻找特定类型的简单模型,那么有时候参数学习是无法找到简单问题的简单解决方案的
  179. '''
  180. #第一个循环网络基准
  181. '''
  182. 门控循环单元(GRU,gated recurrent unit)层的工作原理与LSTM相同。但它做了一些简化,因此运 行的计算代价更低(虽然表示能力可能不如LSTM)。机器学习中到处可以见到这种计算代价与表示能力之间的折中。
  183. '''
  184. #训练并评估一个基于GRU的模型
  185. def build_GRU():
  186. model=Sequential()
  187. model.add(layers.GRU(32,input_shape=(None,float_data.shape[-1])))
  188. model.add(layers.Dense(1))
  189. model.compile(optimizer=RMSprop(),loss='mae')
  190. history1=model.fit_generator(train_gen,
  191. steps_per_epoch=500,
  192. epochs=20,
  193. validation_data=val_gen,
  194. validation_steps=val_steps)
  195. return history1
  196. # acc_loss_plot(build_GRU())#0.28证明了循环网络与序列展平的密集网络相比在这种任务上的优势。但仍有改进的空间
  197. #使用循环dropout来降低过拟合
  198. '''
  199. 在循环层前面应用 dropout,这种正则化会 妨碍学习过程,而不是有所帮助
  200. Yarin Gal 确定了在循环网络中使用 dropout 的正确方法:对每个时间步应该使用相同的 dropout 掩码(dropout mask,相同模式的舍弃单元),而不是让
  201. dropout 掩码随着时间步的增加而随机变化。此外,为 了对 GRU、LSTM 等循环层得到的表示做正则化,应该将不随时间变化的 dropout 掩码应用于层
  202. 的内部循环激活(叫作循环 dropout 掩码)。对每个时间步使用相同的 dropout 掩码,可以让网络 沿着时间正确地传播其学习误差,而随时间随机变
  203. 化的 dropout 掩码则会破坏这个误差信号,并且不利于学习过程
  204. #####循环注意(recurrent attention)和序列掩码 (sequence masking)。这两个概念通常对自然语言处理特别有用
  205. '''
  206. #Yarin Gal 使用 Keras 开展这项研究,并帮助将这种机制直接内置到 Keras 循环层中。因为使用 dropout 正则化的网络总是需要更长的时间才能完全收敛,所以网络训练轮次增加为原来的 2 倍
  207. def build_GRU_with_dropout():
  208. model = Sequential()
  209. model.add(layers.GRU(32,
  210. dropout=0.2,#指定该层输入单元的 dropout 比率
  211. recurrent_dropout=0.2,#指定该层循环单元的 dropout 比率
  212. input_shape=(None, float_data.shape[-1]),
  213. ))
  214. model.add(layers.Dense(1))
  215. model.compile(optimizer=RMSprop(), loss='mae')
  216. history1 = model.fit_generator(train_gen,
  217. steps_per_epoch=500,
  218. epochs=40,
  219. validation_data=val_gen,
  220. validation_steps=val_steps)
  221. return history1
  222. # acc_loss_plot(build_GRU_with_dropout())#发现虽然过拟合速率有所缓解,但mae并没有降低很多
  223. '''
  224. 增加网络容量通常是一个好主意,直到过拟合变成主要的障碍(假设 你已经采取基本步骤来降低过拟合,比如使用 dropout)。只要过拟合不是太严重,那么很可能是容量不足的问题
  225. 增加网络容量的通常做法是------增加每层单元数或增加层数
  226. 循环层堆叠(recurrent layer stacking)是构建更加强大的循环网络的经典方法,例如,目前谷歌翻译算法就是7个大型LSTM 层的堆叠
  227. '''
  228. def build_GRU_with_recurrent_layer_stacking():
  229. model = Sequential()
  230. model.add(layers.GRU(32,
  231. dropout=0.1,#指定该层输入单元的 dropout 比率
  232. recurrent_dropout=0.5,#指定该层循环单元的 dropout 比率
  233. return_sequences=True,#所有中间层都应该返回完整的输出序列(一个3D张量)
  234. input_shape=(None, float_data.shape[-1]),
  235. ))
  236. model.add(layers.GRU(64, activation='relu', dropout=0.1,
  237. recurrent_dropout=0.5))
  238. model.add(layers.Dense(1))
  239. model.compile(optimizer=RMSprop(), loss='mae')
  240. history1 = model.fit_generator(train_gen,
  241. steps_per_epoch=500,
  242. epochs=40,
  243. validation_data=val_gen,
  244. validation_steps=val_steps)
  245. return history1
  246. # acc_loss_plot(build_GRU_with_recurrent_layer_stacking())#结果有所改进,但并不显著。
  247. '''
  248. 因为过拟合仍然不是很严重,所以可以放心地增大每层的大小,以进一步改进验证损失。但这么做的计算成本很高。
  249. 添加一层后模型并没有显著改进,所以你可能发现,提高网络能力的回报在逐渐减小。
  250. '''
  251. #使用双向RNN。
  252. '''
  253. 双向RNN利用了RNN的顺序敏感性:它包含两个普 通RNN,比如你已经学过的 GRU 层和 LSTM 层,每个RN分别沿一个方向对输入序列进行处理(时间正序和时间逆
  254. 序),然后将它们的表示合并在一起。通过沿这两个方向处理序列,双向RNN能够捕捉到可能被单向RNN忽略的模式。
  255. '''
  256. #将输入序列沿着时间维度反转(即将最后一行代码替换为 yield samples[:, ::-1, :], targets)
  257. #执行后发现效果要比之前基于常识的基准方法差很多
  258. '''
  259. GRU 层通常更善于记住最近的数据,而不是久远的数据,与更早的数据点相比,更靠后的天气数据点对问题自然具有更高的预测能力(这也是基于常识的基准方法非常强大的原因)。因此,按时间正序的模型必然会优于时间逆序的模型.
  260. '''
  261. #将其应用于自然语言等问题,比如IMDB的LSTM实例[同样将序列反转]
  262. # x_train = [x[::-1] for x in x_train]
  263. # x_test = [x[::-1] for x in x_test]
  264. '''
  265. #得出模型性能与正序LSTM几乎相同,这证明了一个假设:
  266. 虽然单词顺序对理解语言很重要,但使用哪种顺序并不重要.
  267. 在机器学习中,如果一种数据表示不同但有用,那么总是值得加以利用,这 种表示与其他表示的差异越大越好,它们提供了查看数据的全新角度,抓住了数据中被其他方法忽略的内容,因此可以提高模型在某个任务上的性能。这是集成(ensembling)方法背后的直觉
  268. '''
  269. #双向RNN正是利用这个想法来提高正序RNN的性能。它从两个方向查看数据,从而得到更加丰富的表示,并捕捉到仅使用正序RNN时可能忽略的一些模式
  270. #在 Keras 中将一个双向RNN实例化,我们需要使用 Bidirectional层,它的第一个参数 是一个循环层实例。Bidirectional 对这个循环层创建了第二个单独实例,然后使用一个实例 按正序处理输入序列,另一个实例按逆序处理输入序列
  271. # model.add(layers.Bidirectional(layers.LSTM(32)))
  272. #训练一个双向GRU
  273. def build_bidirect_GRU():
  274. model = Sequential()
  275. model.add(layers.Bidirectional(layers.GRU(32,
  276. dropout=0.2, # 指定该层输入单元的 dropout 比率
  277. recurrent_dropout=0.2, # 指定该层循环单元的 dropout 比率
  278. input_shape=(None, float_data.shape[-1]),
  279. )))
  280. model.add(layers.Dense(1))
  281. model.compile(optimizer=RMSprop(), loss='mae')
  282. history1 = model.fit_generator(train_gen,
  283. steps_per_epoch=500,
  284. epochs=40,
  285. validation_data=val_gen,
  286. validation_steps=val_steps)
  287. return history1
  288. acc_loss_plot(build_bidirect_GRU())
  289. '''
  290. 这个模型的表现与普通 GRU 层差不多一样好。其原因很容易理解:所有的预测能力肯定都 来自于正序的那一半网络,因为我们已经知道,逆序的那一半在这个任务上的表现非常糟糕(本例同样是因为,最近的数据比久远的数据更加重要)
  291. #双向RNN 如果在序列数据中最近的数据比序列开头包含更多的信息,那么这种方法的效果就不明显
  292. '''

 基于常识的基准:

为了提高温度预测问题的性能,你还可以尝试下面这些方法
    1)在堆叠循环层中调节每层的单元个数。当前取值在很大程度上是任意选择的,因此可能不是最优的。
    2)调节 RMSprop 优化器的学习率。 
    3)尝试使用 LSTM 层代替 GRU 层。 
    4)在循环层上面尝试使用更大的密集连接回归器,即更大的 Dense 层或 Dense 层的堆叠。
    5)不要忘记最后在测试集上运行性能最佳的模型(即验证MAE最小的模型)。否则,你开发的网络架构将会对验证集过拟合
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/801789
推荐阅读
相关标签
  

闽ICP备14008679号