趋近智
文本数据需要分词 (tokenization)和嵌入 (embedding),而时间序列数据在使用循环神经网络 (neural network)(RNN)前,也有其特有的预处理要求。时间序列通常由在连续时间点上获取的测量值构成,每个步骤可能记录多个变量。与神经网络中使用的其他数据类型一样,数值稳定性和一致的特征表示是必需的。此外,我们需要将时间序列的连续数据流构造为适合RNN输入的离散序列。
本节介绍时间序列数据的两个主要预处理步骤:归一化 (normalization)和窗口化。我们还将简要谈及特征处理和潜在的缺失值问题。
神经网络 (neural network)(包括RNN)在输入特征处于相似尺度时,通常训练效果更好。时间序列数据的特征值可能存在明显不同的范围(例如,摄氏温度与帕斯卡大气压)。大的输入值可能导致大的梯度,潜在地引起训练不稳定(梯度爆炸),而非常小的值可能会减慢学习速度。
两种常见的缩放技术是最小-最大缩放和标准化:
此方法将数据缩放到固定范围,通常是[0, 1]或[-1, 1]。缩放到[0, 1]的公式是:
其中,和是训练数据集中该特征的最小值和最大值。
此方法将数据缩放,使其均值为0,标准差为1。公式为:
其中,是训练数据集中该特征的均值,是标准差。
时间序列(以及大多数其他机器学习 (machine learning)数据)预处理中的一个重要之处在于,您必须仅在训练数据上拟合缩放器(计算、、、)。然后,您使用这个已拟合的缩放器来转换训练集、验证集和测试集。如果在包括验证或测试数据在内的整个数据集上拟合缩放器,会导致未来或未见数据的信息泄露到训练过程中,从而得出过于乐观的性能评估。
# 使用scikit-learn的Python示例
from sklearn.preprocessing import StandardScaler
import numpy as np
# 假设train_data, validation_data, test_data是NumPy数组
# 在窗口化之前的形状可能为 (样本数量, 特征数量)
scaler = StandardScaler()
# 仅在训练数据上拟合
scaler.fit(train_data)
# 将*相同*的已拟合缩放器应用于所有数据集
train_scaled = scaler.transform(train_data)
validation_scaled = scaler.transform(validation_data)
test_scaled = scaler.transform(test_data)
# 稍后,当对新数据进行预测时,使用相同的缩放器:
# new_data_scaled = scaler.transform(new_data)
# 如有需要,将预测结果还原到原始尺度:
# predictions_original_scale = scaler.inverse_transform(predictions_scaled)
RNN按序列处理数据。对于典型的时间序列预测任务,我们不会将整个历史数据作为一个序列输入。相反,我们使用“滑动窗口”方法来生成多个较小的输入序列及其对应的目标值。
假设您有一个单变量时间序列(每个时间步一个测量值):[10, 20, 30, 40, 50, 60, 70, 80]。
我们需要决定:
我们选择输入窗口大小 和输出范围 。我们将此窗口在数据上滑动:
[10, 20, 30] -> 目标 [40][20, 30, 40] -> 目标 [50][30, 40, 50] -> 目标 [60][40, 50, 60] -> 目标 [70][50, 60, 70] -> 目标 [80]每个“输入 -> 目标”对都成为一个用于训练或评估的样本。输入部分将构成我们RNN输入张量的时间步维度。
N_{in})来预测单个未来步(N_{out}=1)。常用于简单预测。RNN通常处理输入序列,然后将一个全连接层应用于最终隐藏状态以生成输出预测。N_{in})预测多个未来步(N_{out} > 1)。例如,使用3个过去步预测接下来的2个步。
[10, 20, 30] -> 目标 [40, 50]return_sequences=True,或使用特定的解码器结构)。选择完全取决于您要解决的问题。对于预测,多对一(预测下一步)和多对多(预测多个未来步)是常见的模式。
这通常通过基本的数组操作完成,例如使用NumPy切片或专用库函数(如TensorFlow中的tf.keras.utils.timeseries_dataset_from_array)。
# 用于窗口化(多对一)的Python函数
def create_windows(data, input_width, label_width, shift):
"""
为时间序列预测创建窗口化数据。
参数:
data: 时间序列数据(NumPy数组,通常是2D:时间 x 特征)。
input_width: 输入窗口中的时间步数。
label_width: 输出标签窗口中的时间步数(对于简单的下一步预测通常为1)。
shift: 输入窗口末尾与标签窗口开始之间的偏移量。
对于预测紧随输入窗口的下一个步,shift=label_width。
返回:
inputs: 输入窗口的列表或数组。
labels: 相应标签的列表或数组。
"""
inputs = []
labels = []
total_window_size = input_width + shift
end_index = len(data) - total_window_size + 1
for i in range(end_index):
input_slice = data[i : i + input_width]
label_start_index = i + input_width + shift - label_width
label_slice = data[label_start_index : label_start_index + label_width]
inputs.append(input_slice)
labels.append(label_slice)
return np.array(inputs), np.array(labels)
# 示例用法:
# 假设'scaled_data'是我们预处理后的时间序列(例如,形状为 [1000, 1] 或 [1000, num_features])
INPUT_WIDTH = 24 # 使用过去24小时的数据
LABEL_WIDTH = 1 # 预测未来1小时
SHIFT = 1 # 预测紧随输入窗口的下一步
inputs, labels = create_windows(scaled_data, INPUT_WIDTH, LABEL_WIDTH, SHIFT)
# 结果形状(近似值,取决于总数据长度):
# inputs.shape -> (样本数量, INPUT_WIDTH, 特征数量) 例如,(976, 24, 1)
# labels.shape -> (样本数量, LABEL_WIDTH, 特征数量) 例如,(976, 1, 1)
# 如果label_width为1,通常标签会被压缩:(样本数量, 特征数量)
现在这个inputs数组的形状是 (样本数量, 时间步长, 特征数量),这正是RNN层所期望的(在分组为批次之后)。
特征维度。确保所有特征都经过适当缩放(通常使用相同的方法,如标准化,并对训练数据中的每个特征独立进行拟合)。窗口化过程保持不变,但窗口中的每个时间步都将包含多个特征值。"时间序列常常包含缺失值。常见策略包括:"
通常最好在缩放和窗口化之前处理缺失值,尽管具体选择取决于数据的性质和缺失的程度。如果使用填充,请记住这也为您的数据引入了假设。遮蔽(在文本填充部分已介绍)有时可以适应缺失步,但标准RNN层可能不支持,除非进行自定义实现或使用特定框架功能。
通过应用归一化 (normalization)和窗口化,您可以将原始时间序列测量值转换为结构化、缩放后的序列,这些序列可用于训练LSTMs和GRUs等高效的循环模型。请记住,在训练、验证和测试数据集中一致地应用这些步骤,并且始终仅从训练部分获取缩放参数 (parameter)和填充统计数据。
这部分内容有帮助吗?
© 2026 ApX Machine LearningAI伦理与透明度•