温度预测问题
基本就是数据的分析
# 观察数据集中的数据
import os
data_dir = r'G:\pycharm\tensorflow\Python深度学习'
fname = os.path.join(data_dir, 'jena_climate_2009_2016.csv')
f = open(fname)
data = f.read()
f.close()
lines = data.split('\n')
header = lines[0].split(',')
lines = lines[1:]
print(header)
print(len(lines))
# 解析数据
import numpy as np
float_data = np.zeros((len(lines), len(header) - 1))
print(lines[1])
for i, line in enumerate(lines):
values = [float(x) for x in line.split(',')[1:]]
float_data[i,:] = values
print(float_data)
# 绘制温度时间序列
from matplotlib import pyplot as plt
temp = float_data[:, 1] #温度(单位:摄氏度)
plt.plot(range(len(temp)), temp)
# 绘制前10天的温度时间序列
plt.plot(range(1440), temp[:1440])
准备数据
一个时间步是10分钟,每steps个时间步采样一次数据,给定过去lookback个时间步以内的数据,能否预测delay个时间步之后的温度?用到的参数值如下:
- lookback = 720:给定过去5天内的观测数据。
- steps = 6:观测数据的采样频率是每小时一个数据点
- delay = 144:目标是未来24小时之后的数据
- 将数据预处理为神经网络可以处理的格式,需要对每个时间序列分别做标准化,让它们在相似的范围内都取较小的值。
- 编写一个Python生成器,以当前的浮点数据数组作为输入,并从中最近的数据中生成数据批量,同时生成未来的目标温度。
预处理数据的方法是,将每个时间序列减去其平均值,然后除以其标准差。我们将使用前200 000个时间步作为训练数据,所以只对这部分数据计算平均值和标准差。
下面的代码给出了要用到的生成器。它生成了一个元组(samples, targets),其中samples是输入数据的一个批量,targets是对应的目标温度数组。生成器参数如下:# 数据标准化 mean = float_data[:200000].mean(axis=0) float_data -= mean #平均值 std = float_data[:200000].std(axis=0) #标准差 float_data /= std
- data:浮点数数据组成的原始数组
- lookback:输入数据应该包括过去多少个时间步
- delay:目标应该在未来多少个时间步之后
- min_index和max_index:data数组中的索引,用于界定需要抽取哪些时间步。这有助于保存一部分数据用于验证、另一部分用于测试。
- shuffle:是打乱样本,还是按顺序抽取样本
- batch_size:每个批量的样本数
step:数据采样的周期,我们设置为6,为的是每小时抽取一个数据点
def generator(data, lookback, delay, min_index, max_index, shuffle=False, batch_size=128, step=6): if max_index is None: max_index = len(data) - delay - 1 i = min_index + lookback while 1: if shuffle: rows = np.random.randint(min_index + lookback, max_index, size=batch_size) else: if i + batch_size >= max_index: i = min_index + lookback rows = np.arrange(i, min(i + batch_size, max_index)) i += len(rows) samples = np.zeros((len(rows), lookback // step, data.shape[-1])) targets = np.zeros((len(rows), )) for j, row in enumerate(rows): indices = range(rows[j] - lookback, rows[j], step) sample[j] = data[indices] targets[j] = data[rows[j] + delay][2] yield sample, target
np.arange
用于生成带起点和终点的特定步长的排列。
yield
lookback = 1440 step = 6 delay = 144 batch_size = 128
train_gen = generator(float_data, lookback=lookback, delay=delay, min_index=0, max_index=200000, shuffle=True, step=step, batch_size=batch_size) val_gen = generator(float_data, lookback=lookback, delay=delay, min_index=200001, max_index=300000, shuffle=True, step=step, batch_size=batch_size) test_gen = generator(float_data, lookback=lookback, delay=delay, min_index=300001, max_index=None, shuffle=True, step=step, batch_size=batch_size)
val_steps = (300000 - 200001 -lookback) // batch_size #为了查看整个验证集需要从val_gen中抽取多少次 test_steps = (len(float_data) - 300001 -lookback) // batch_size #为了查看整个测试集需要从test_gen中抽取多少次
一种基于常识的、非机器学习的基准方法
面对一个尚没有已知解决方案的新问题时,这种基于常识的基准方法很有用。一个经典的例子就是不平衡的分类任务,其中某些类别比其他类别更常见。如果数据集中包含90%的A和10%的类别B,那么分类任务的一种基于常识的方法是对新样本始终预测类别“A”。这种分类器的总体精度为90%,因此任何基于学习的方法在精度高于90%时才能证明其有效性。有时候,这种基本的基准方法可能很难打败。
在本例中,我们可以放心假设,温度时间序列是连续的(明天的温度很可能接近今天的温度),并且具有每天的周期性变化。因此,一种基于常识的方法就是始终预测24小时后的温度等于现在的温度。我们使用平均绝对误差(MAE)指标来评估这种方法。
下面是评估的循环代码
计算符合常识的基准方法的MAE
def evaluate_native_method():
batch_maes = []
samples, targets = next(val_gen) preds = samples[:, -1, 1] mae = np.mean(np.abs(preds - targets)) batch_maes.append(mae)
print(np.mean(batch_maes))
evaluate_native_method()
将MAE转换为摄氏温度误差
celsius_mae = 0.29 * std1
# 一种基本的机器学习方法
尝试机器学习方法之前,建立一个基于常识的基准方法是很有用的,同样,在开始研究复杂且计算代价很高的模型(比如RNN)之前,尝试使用简单且计算代价低的机器学习模型也是很有用的,比如小型的密集连接网络。这可以保证进一步增加问题的复杂度是合理的,并且会带来真正的好处。
下面的代码给出了一个密集连接模型,首先将数据展平,然后通过两个Dense层并运行。注意,最后一个Dense层没有使用激活函数,这对于回归问题是很常见的。我们使用MAE作为损失。
训练并评估一个密集连接模型
from keras.models import Sequential
from keras import layers
model = Sequential()
model.add(layers.Flatten(input_shape=(lookback // step, float_data.shape[-1])))
model.add(layers.Dense(32, activation=’relu’))
model.add(layers.Dense(1))
model.compile(optimizer=RMSprop(), loss=’mae’)
绘制结果
import matplotlib.pyplot as plt
loss = history.history[‘loss’]
epochs = range(1, len(loss) + 1)
plt.figure()
plt.plot(epochs, loss, ‘bo’, label=’Training loss’)
plt.plot(epochs, val_loss, ‘b’, label=’validation loss’)
plt.legend()
# 第一个循环网络基准
将数据展平,从数据中删除了时间的概念。我们将使用**GRU**循环网络层来再次进行训练,GRU同LSTM相似但做了一些简化,运算代价更低(虽然表示能力可能不如LSTM)。
model = Sequential()
model.add(layers.GRU(32, input_shape=(None, float_data.shape[-1])))
model.add(layers.Dense(1))
model.compile(optimizer=RMSprop(), loss=’mae’)
history = model.fit_generator(train_gen, steps_per_epoch=500, epochs=20, validation_data=val_gen, validation_steps=val_steps)