时序数据深度学习笔记——DNN(一)

 一、深度学习

        当数据有多个季节周期,很可能会导致残差不是正态分布并且相关,因此无法使用SARIMAX 模型,此时便可以通过深度学习利用两个季节的信息来做出预测。

        对于时间序列预测,一般可以创建三种类型深度学习模型: 单步模型、多步模型和多输出模型。单步模式是三种模式中最简单的一种,其输入可以是任意长度,输出是一个单一的值,代表着对未来一个变量的预测。

1、线性模型

        线性模型是深度学习中可以实现的最简单的架构,其没有隐藏层,每个输入特征都被简单地赋予一个权重,然后通过组合输出对目标的预测,如同传统的线性回归。

2、激活函数

        激活函数在神经网络的每个神经元中,负责从输入数据中生成输出。其可分为线性激活函数与非线性激活函数,如果使用线性激活函数,模型将只建模线性关系;而为了模拟数据中的非线性关系,则须使用非线性激活函数,非线性激活函数大致分为:ReLU、softmax、tanh。其中ReLU是深度学习中使用最广泛的激活函数,一般在一个密集层和一个隐藏层时使用。

二、单步模式使用

1、数据处理

1.1 数据加载

        通过数据概览以及图像观测,可发现traffic_volume数据以星期为周期反复变化,并且rain_1h与snow_1h基本为0,对于预测帮助不大,可移除,另外时间属性字段需要特殊处理。

df = pd.read_csv('metro_interstate_traffic_volume_preprocessed.csv')
print(df.head())
print(df.shape)
print(df.describe().transpose())

              date_time    temp  rain_1h  snow_1h  clouds_all  traffic_volume
0  2016-09-29 17:00:00  291.75      0.0        0           0          5551.0
1  2016-09-29 18:00:00  290.36      0.0        0           0          4132.0
2  2016-09-29 19:00:00  287.86      0.0        0           0          3435.0
3  2016-09-29 20:00:00  285.91      0.0        0           0          2765.0
4  2016-09-29 21:00:00  284.31      0.0        0           0          2443.0
(17551, 6)
                  count         mean          std  ...      50%      75%      max
temp            17551.0   281.416203    12.688262  ...   282.41   291.89   310.07
rain_1h         17551.0     0.025523     0.259794  ...     0.00     0.00    10.60
snow_1h         17551.0     0.000000     0.000000  ...     0.00     0.00     0.00
clouds_all      17551.0    42.034129    39.065960  ...    40.00    90.00   100.00
traffic_volume  17551.0  3321.484588  1969.223949  ...  3518.00  4943.00  7280.00

[5 rows x 8 columns]

时序数据深度学习笔记——DNN(一)_第1张图片

1.2 数据处理

        a、删除rain_1h与snow_1h字段

cols_to_drop = ['rain_1h', 'snow_1h']
df = df.drop(cols_to_drop, axis=1)

         b、时间属性字段转换

        将时间属性数据通过正弦、余弦方法转换,保留其循环周期性

timestamp_s = pd.to_datetime(df['date_time']).map(datetime.datetime.timestamp)
day = 24 * 60 * 60
df['day_sin'] = (np.sin(timestamp_s * (2*np.pi/day))).values
df['day_cos'] = (np.cos(timestamp_s * (2*np.pi/day))).values
df = df.drop(['date_time'], axis=1)

时序数据深度学习笔记——DNN(一)_第2张图片

 1.3 数据拆分

        将数据集按7:2:1拆分为训练集、验证集与测试集

n = len(df)
train_df = df[0:int(n*0.7)]
val_df = df[int(n*0.7):int(n*0.9)]
test_df = df[int(n*0.9):]

 1.4 数据缩放与保存

from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
scaler.fit(train_df)
train_df[train_df.columns] = scaler.transform(train_df[train_df.columns])
val_df[val_df.columns] = scaler.transform(val_df[val_df.columns])
test_df[test_df.columns] = scaler.transform(test_df[test_df.columns])

train_df.to_csv('data/train.csv')
val_df.to_csv('data/val.csv')
test_df.to_csv('data/test.csv')

                          count      mean       std  ...       50%       75%  max
temp            12285.0  0.555681  0.196527  ...  0.557913  0.715072  1.0
clouds_all      12285.0  0.431034  0.393716  ...  0.400000  0.900000  1.0
traffic_volume  12285.0  0.445735  0.273635  ...  0.473141  0.671271  1.0
day_sin         12285.0  0.499885  0.353534  ...  0.500000  0.853553  1.0
day_cos         12285.0  0.500031  0.353602  ...  0.500000  0.853553  1.0


2、单步模式数据预测

2.1 创建数据窗口类

        主要控制输入长度、标签长度、移位以及所需预测的字段,通过这些参数决定预测的范围。

class DataWindow():
    def __init__(self, input_width, label_width, shift,
                 train_df=train_df, val_df=val_df, test_df=test_df,
                 label_columns=None):

        self.train_df = train_df
        self.val_df = val_df
        self.test_df = test_df

        self.label_columns = label_columns  # 需要预测的列名
        if label_columns is not None:
            self.label_columns_indices = {name: i for i, name in enumerate(label_columns)}  # 名称和索引为标签列,用于绘图
        self.column_indices = {name: i for i, name in enumerate(train_df.columns)}  # 用于从目标变量分离特性

        self.input_width = input_width
        self.label_width = label_width
        self.shift = shift

        self.total_window_size = input_width + shift

        self.input_slice = slice(0, input_width)  # 对序列进行切片
        self.input_indices = np.arange(self.total_window_size)[self.input_slice] #分配索引,用于绘图
        self.label_start = self.total_window_size - self.label_width #获取索引标签起始位置,总窗口大小减去标签宽度

        self.labels_slice = slice(self.label_start, None)   #对标签序列进行切片
        self.label_indices = np.arange(self.total_window_size)[self.labels_slice]

    def split_to_inputs_labels(self, features):
        inputs = features[:, self.input_slice, :]   #切片窗口用于输入的使用
        labels = features[:, self.labels_slice, :]  #切片窗口用于标签的使用
        if self.label_columns is not None:  #如果有多个目标,则堆叠标签
            labels = tf.stack(
                [labels[:, :, self.column_indices[name]] for name in self.label_columns],
                axis=-1
            )
        inputs.set_shape([None, self.input_width, None])    #此处只指定时间维度[batch,time, features]
        labels.set_shape([None, self.label_width, None])

        return inputs, labels

    def plot(self, model=None, plot_col='traffic_volume', max_subplots=3):
        inputs, labels = self.sample_batch

        plt.figure(figsize=(12, 8))
        plot_col_index = self.column_indices[plot_col]
        max_n = min(max_subplots, len(inputs))

        for n in range(max_n):
            plt.subplot(3, 1, n + 1)
            plt.ylabel(f'{plot_col} [scaled]')
            plt.plot(self.input_indices, inputs[n, :, plot_col_index],
                     label='Inputs', marker='.', zorder=-10)    #绘制输入,连续的蓝线

            if self.label_columns:
                label_col_index = self.label_columns_indices.get(plot_col, None)
            else:
                label_col_index = plot_col_index

            if label_col_index is None:
                continue

            plt.scatter(self.label_indices, labels[n, :, label_col_index],
                        edgecolors='k', marker='s', label='Labels', c='green', s=64)    #绘制标签或实际数值,绿色方块
            if model is not None:
                predictions = model(inputs)
                plt.scatter(self.label_indices, predictions[n, :, label_col_index],
                            marker='X', edgecolors='k', label='Predictions',
                            c='red', s=64)  #绘制预测,红十字

            if n == 0:
                plt.legend()

        plt.xlabel('Time (h)')

    def make_dataset(self, data):
        data = np.array(data, dtype=np.float32)
        ds = tf.keras.preprocessing.timeseries_dataset_from_array(
            data=data,  #对应于训练集、验证集或测试集
            targets=None,   #设置为none,因为由函数split_to_inputs_labels处理
            sequence_length=self.total_window_size, #定义数组总长度,等同于总窗口长度
            sequence_stride=1,  #定义每个序列的时间步长,此处希望序列是连续的,因此设置为1
            shuffle=True,   #排序序列,数据仍然按时间顺序排列
            batch_size=32   #定义单个批处理的序列数
        )

        ds = ds.map(self.split_to_inputs_labels)
        return ds

    @property
    def train(self):
        return self.make_dataset(self.train_df)

    @property
    def val(self):
        return self.make_dataset(self.val_df)

    @property
    def test(self):
        return self.make_dataset(self.test_df)

    @property
    def sample_batch(self): #获取用于绘图的示例数据,如果样本批处理不存在,将检索一个样本批处理并换成它
        result = getattr(self, '_sample_batch', None)
        if result is None:
            result = next(iter(self.train))
            self._sample_batch = result
        return result

2.2 创建基线类

        将最后的观测值作为预测结果

class Baseline(Model):
    def __init__(self, label_index=None):
        super().__init__()
        self.label_index = label_index

    def call(self, inputs):
        if self.label_index is None:    #如果未指定目标,则返回所有列,用于预测所有列的多输出模型
            return inputs
        else:
            result = inputs[:, :, self.label_index] #返回给定目标变量的输入
            return result[:, :, tf.newaxis]

2.3 创建预测基线

single_step_window = DataWindow(input_width=1, label_width=1, shift=1, label_columns=['traffic_volume'])
wide_window = DataWindow(input_width=24, label_width=24, shift=1, label_columns=['traffic_volume'])

column_indices = {name: i for i, name in enumerate(train_df.columns)}   #生成训练集中每一列的索引

baseline_last = Baseline(label_index=column_indices['traffic_volume'])  #传输目标列索引的基线类

baseline_last.compile(loss=MeanSquaredError(), metrics=[MeanAbsoluteError()])   #编译模型生成预测

val_performance = {}    #保存验证集的MAE的字典
performance = {}    #保存测试集的MAE的字典

val_performance['Baseline - Last'] = baseline_last.evaluate(single_step_window.val) #存储验证集基准线的MAE
performance['Baseline - Last'] = baseline_last.evaluate(single_step_window.test, verbose=0) #存储测试集基准线的MAE

wide_window.plot(baseline_last)
plt.show()

时序数据深度学习笔记——DNN(一)_第3张图片

 2.4 使用单步线性模型

linear = Sequential([
    Dense(units=1)  #把单位数量指定为 1,因为模型只能输出一个值: 下一个时间步长的交通流量预测
])

history = compile_and_fit(linear, single_step_window)   #训练模型

val_performance['Linear'] = linear.evaluate(single_step_window.val)
performance['Linear'] = linear.evaluate(single_step_window.test, verbose=0)

wide_window.plot(linear)
plt.show()

时序数据深度学习笔记——DNN(一)_第4张图片

2.5 使用单步DNN模型

dense = Sequential([
    Dense(units=64, activation='relu'), #第一个隐藏层有 64 个神经元。指定激活函数为 ReLU
    Dense(units=64, activation='relu'),
    Dense(units=1)  #输出层只有一个神经元,因为我们只输出一个值
])
history = compile_and_fit(dense, single_step_window)
val_performance['Dense'] = dense.evaluate(single_step_window.val)
performance['Dense'] = dense.evaluate(single_step_window.test, verbose=0)
wide_window.plot(dense)
plt.show()

时序数据深度学习笔记——DNN(一)_第5张图片

2.6 MAE结果比较

        通过MAE比较可以发现单步模型中,DNN的效果最佳

mae_val = [v[1] for v in val_performance.values()]
mae_test = [v[1] for v in performance.values()]

x = np.arange(len(performance))

fig, ax = plt.subplots()
ax.bar(x - 0.15, mae_val, width=0.25, color='black', edgecolor='black', label='Validation')
ax.bar(x + 0.15, mae_test, width=0.25, color='white', edgecolor='black', hatch='/', label='Test')
ax.set_ylabel('Mean absolute error')
ax.set_xlabel('Models')

for index, value in enumerate(mae_val):
    plt.text(x=index - 0.15, y=value + 0.0025, s=str(round(value, 3)), ha='center')

for index, value in enumerate(mae_test):
    plt.text(x=index + 0.15, y=value + 0.0025, s=str(round(value, 3)), ha='center')

plt.ylim(0, 0.1)
plt.xticks(ticks=x, labels=performance.keys())
plt.legend(loc='best')
plt.tight_layout()
plt.show()

 时序数据深度学习笔记——DNN(一)_第6张图片

 代码地址:https://download.csdn.net/download/HughYue1990/86743129

数据集下载地址: https://download.csdn.net/download/HughYue1990/86744775

你可能感兴趣的:(学习,时序数据库,python,深度学习)