时间序列预测(八)——正则化+过拟合、欠拟合、

在介绍正则化之前,先介绍几个概念:

1. 过拟合(Overfitting)

过拟合是指模型在训练集上表现得非常好,但在测试集上表现不佳。这通常是因为模型学习到了训练数据中的噪声不必要的细节,导致模型在新数据上的泛化能力下降。

主要表现

  • 训练误差低,但测试误差高。
  • 预测结果对训练数据的微小变化非常敏感。

解决过拟合的方法

  • 正则化:使用 L1、L2 正则化或 Dropout 降低模型复杂度。
  • 增加数据量:使用数据增强或收集更多样本。
  • 简化模型:减少模型的层数、神经元数或选择更简单的模型。

2. 欠拟合(Underfitting)

欠拟合是指模型在训练集和测试集上都表现不佳,无法很好地捕捉数据的模式或趋势。这通常是因为模型的复杂度不够,无法学习到数据中的有效特征。

主要表现

  • 训练误差和测试误差都较高。
  • 模型无法充分捕捉数据特征,预测结果较为简单,无法反映数据的实际趋势。

解决欠拟合的方法

  • 增加模型复杂度:增加模型层数、神经元数,或选择更复杂的模型。
  • 增加特征:从数据中提取更多有效特征(如多项式特征)。
  • 增加训练轮数:多训练几轮,确保模型充分学习到数据模式。

下图展示一个简单的回归问题,欠拟合、适度拟合和过拟合三种模型在数据上的表现:

  • Degree=1(欠拟合):模型的复杂度过低,无法很好地捕捉数据的非线性特征。
  • Degree=3(适度拟合):模型较好地拟合了数据的趋势,误差较低。
  • Degree=15(过拟合):模型在训练数据上拟合得很好,但曲线波动大,对新数据的泛化能力差。

接下来介绍正则化。

正则化是一种用于防止机器学习模型过拟合的技术。正则化通过在损失函数中加入额外的惩罚项,使得模型更简单且泛化能力更强,避免在训练集上表现很好而在测试集上表现不佳的情况。常见的正则化方法有 L1 正则化L2 正则化Dropout

1. L1 正则化

L1 正则化(也叫 Lasso 正则化)会在损失函数中增加一个与权重绝对值成正比的惩罚项,使得模型倾向于让某些权重变为零,从而实现特征选择的效果。

优点:

使部分权重变为零,达到稀疏特征选择的效果。

可以用来理解哪些特征对模型预测最重要。

Python 实现:

from sklearn.linear_model import Lasso

lasso_model = Lasso(alpha=0.1)  # alpha 代表 λ
lasso_model.fit(X_train, y_train)

 2. L2 正则化

L2 正则化(也叫 Ridge 正则化)在损失函数中加入权重平方的惩罚项。这种方法不会将权重变成零,但会使其尽可能接近零,从而使模型更平滑。

优点:

有效减少模型的复杂度。

对于多重共线性的特征有良好的控制效果。

Python 实现:

from sklearn.linear_model import Ridge

ridge_model = Ridge(alpha=0.1)  # alpha 代表 λ
ridge_model.fit(X_train, y_train)

3. Elastic Net

Elastic Net 是 L1 和 L2 正则化的结合,可以根据需要平衡稀疏性和稳定性。Elastic Net 的损失函数包含了 L1 和 L2 惩罚项,公式如下:

Python 实现:

from sklearn.linear_model import ElasticNet

elastic_net_model = ElasticNet(alpha=0.1, l1_ratio=0.5)  # l1_ratio 代表 ρ
elastic_net_model.fit(X_train, y_train)

4. Dropout 正则化

Dropout是一种适用于神经网络的正则化方法,它通过在训练过程中随机“丢弃”一部分神经元(即将其输出设置为零)来防止过拟合。测试时将所有神经元的输出乘以一个比例因子,以保持训练和测试的一致性。这样模型不会过于依赖某些特定的神经元,提高了模型的泛化能力。

Python 实现:

from tensorflow.keras.models import Sequential  
# 从tensorflow.keras.layers导入Dense和Dropout层  
from tensorflow.keras.layers import Dense, Dropout  
  
# 创建一个Sequential模型实例  
model = Sequential([  
    # 添加第一个全连接层(Dense层),有64个神经元,激活函数为ReLU,input_shape代表输入数据的形状  例如(784,)对于28x28的图像数据  
    Dense(64, activation='relu', input_shape=(input_shape,)),  
    # 添加Dropout层,用于减少过拟合,丢弃率为50%,即在训练过程中随机丢弃一半的神经元  
    Dropout(0.5),    
    # 添加第二个全连接层,有64个神经元,激活函数同样为ReLU  
    Dense(64, activation='relu'),  
    # 再次添加Dropout层,丢弃率仍为50%  
    Dropout(0.5),  
    # 添加输出层,这是一个全连接层,但只有1个神经元,通常用于回归任务  对于回归问题,默认是线性激活
    Dense(1)  
])  
  
# 编译模型,指定优化器为Adam,损失函数为均方误差(MSE),这通常用于回归任务  
model.compile(optimizer='adam', loss='mse')

5. 数据正则化

虽然严格来说不属于正则化项,但标准化或归一化数据可以减少模型过拟合的可能性,帮助模型更稳定地收敛。常用的包括 标准化(Standardization) 和 归一化(Normalization)。标准化将数据缩放为均值为 0、标准差为 1,归一化则将数据缩放到特定区间(通常是 [0, 1] 或 [-1, 1])。

Python 实现:

# 从sklearn.preprocessing模块导入StandardScaler和MinMaxScaler类  
from sklearn.preprocessing import StandardScaler, MinMaxScaler  
  
# 标准化  
scaler = StandardScaler()  # StandardScaler用于将特征缩放到均值为0,标准差为1的分布上
  
X_train_scaled = scaler.fit_transform(X_train)  # 使用fit_transform方法对训练数据X_train进行拟合和转换
  
# 归一化  
scaler = MinMaxScaler()  # MinMaxScaler用于将特征缩放到给定的最小值和最大值之间(通常是0和1)  
X_train_normalized = scaler.fit_transform(X_train)

6.早停法 (Early Stopping)

早停法在训练过程中监测验证集误差,当验证误差不再减少时提前停止训练。这样可以防止模型在训练集上过度拟合,帮助模型达到更好的泛化效果。

优点

实现简单,只需在验证集上检测误差变化。

不增加额外的惩罚项,直接通过优化训练步骤控制过拟合。

Python 实现:

from tensorflow.keras.callbacks import EarlyStopping
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

# 构建简单神经网络
model = Sequential([
    Dense(64, activation='relu', input_shape=(input_shape,)),
    Dense(64, activation='relu'),
    Dense(1)
])
model.compile(optimizer='adam', loss='mse', metrics=['mae'])

# 使用早停法
early_stopping = EarlyStopping(
    monitor='val_loss',  # 监测验证集损失
    patience=5,          # 容忍验证集损失连续5次无改善
    restore_best_weights=True
)

# 训练模型
history = model.fit(
    X_train, y_train,
    epochs=100,
    validation_data=(X_val, y_val),
    callbacks=[early_stopping]
)

7. 数据增强 (Data Augmentation)

数据增强通过生成新的数据样本来扩大数据集的大小,帮助模型提升泛化能力。例如,在图像分类中可以通过旋转、翻转、缩放等操作生成新的图像样本,从而减少模型的过拟合风险。通常用于计算机视觉任务。

优点

增加数据集多样性,有助于模型学习更丰富的特征。

不依赖于模型结构,可与其他正则化方法组合使用。

Python 实现:

from tensorflow.keras.preprocessing.image import ImageDataGenerator

# 定义数据增强参数
datagen = ImageDataGenerator(
    rotation_range=40,        # 随机旋转角度
    width_shift_range=0.2,    # 随机水平平移
    height_shift_range=0.2,   # 随机竖直平移
    shear_range=0.2,          # 随机错切变换
    zoom_range=0.2,           # 随机缩放
    horizontal_flip=True,     # 随机水平翻转
    fill_mode='nearest'       # 填充方式
)

# 将增强的数据传入模型
train_generator = datagen.flow(X_train, y_train, batch_size=32)
model.fit(train_generator, epochs=50)

8. 批量归一化(Batch Normalization)

批量归一化通过在网络的每一层加入一个归一化步骤,将数据标准化为均值为0、方差为1的分布。公式如下:

Python 实现:

from tensorflow.keras.layers import BatchNormalization

model = Sequential([
    Dense(64, input_shape=(input_shape,), activation='relu'),
    BatchNormalization(),  # 添加批量归一化层
    Dense(64, activation='relu'),
    BatchNormalization(),
    Dense(1)
])
model.compile(optimizer='adam', loss='mse')

最后,用一个多项式回归模型来拟合带有噪声的二次函数。为了展示过拟合和正则化的效果,用 15 阶多项式拟合数据并对比无正则化与正则化模型的结果。以下是代码:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression, Ridge
from sklearn.metrics import mean_squared_error

# 生成示例数据:二次曲线加噪声
np.random.seed(42)
X = np.sort(5 * np.random.rand(20, 1), axis=0)  # 输入范围为 [0, 5] 的随机点
y = 2 * X**2 + X + 3 + np.random.randn(20, 1)    # y = 2x^2 + x + 3 加上噪声

# 创建高阶多项式特征
poly_features = PolynomialFeatures(degree=15)  # 15阶多项式会导致过拟合
X_poly = poly_features.fit_transform(X)

# 普通回归模型(容易过拟合)
model_no_reg = LinearRegression()
model_no_reg.fit(X_poly, y)

# 带 L2 正则化的回归模型(Ridge 回归)
model_with_reg = Ridge(alpha=1)  # alpha 是正则化强度,值越大正则化越强
model_with_reg.fit(X_poly, y)

# 生成测试数据
X_test = np.linspace(0, 5, 100).reshape(-1, 1)
X_test_poly = poly_features.transform(X_test)  # 将测试数据转换为多项式特征
y_pred_no_reg = model_no_reg.predict(X_test_poly)  # 无正则化模型的预测结果
y_pred_with_reg = model_with_reg.predict(X_test_poly)  # 正则化模型的预测结果

# 绘制结果
plt.figure(figsize=(12, 6))

# 绘制训练数据和真实曲线
plt.scatter(X, y, color="blue", label="Training data")
plt.plot(X_test, 2 * X_test**2 + X_test + 3, color="green", linestyle="--", label="True function")

# 绘制无正则化模型预测曲线(容易过拟合)
plt.plot(X_test, y_pred_no_reg, color="red", label="Prediction without Regularization")

# 绘制带 L2 正则化模型预测曲线(缓解过拟合)
plt.plot(X_test, y_pred_with_reg, color="purple", label="Prediction with L2 Regularization")

# 图例和标题
plt.xlabel("X")
plt.ylabel("y")
plt.title("Overfitting and Regularization in Polynomial Regression")
plt.legend()
plt.show()

# 计算和输出训练误差(均方误差)
mse_no_reg = mean_squared_error(y, model_no_reg.predict(X_poly))
mse_with_reg = mean_squared_error(y, model_with_reg.predict(X_poly))
print("Mean Squared Error without Regularization:", mse_no_reg)
print("Mean Squared Error with L2 Regularization:", mse_with_reg)

输出结果

结果分析

在图中,可以看到:

  • 红色曲线(无正则化)在训练数据上完全拟合,表现出过拟合特性。
  • 紫色曲线(带正则化)更平滑,避免了过度拟合,符合数据的真实趋势。

 别忘了给这篇文章点个赞哦,非常感谢。我也正处于学习的过程,如果有问题,欢迎在评论区留言讨论,一起学习!