人工智能-过拟合,欠拟合以及模型泛化

1 篇文章 0 订阅
1 篇文章 0 订阅

这篇文章包含的内容比较多,我将从 多项式回归模型 中引出 过拟合、欠拟合、模型泛化问题 以及Ridge回归、LASSO回归两个用于优化过拟合问题的模型

多项式回归

在之前我们提到过 简单线性回归、多元线性回归;都是假设特征与样本目标值之间是存在线性关系的,但实际应用中存在简单线性关系的场景是少之又少的;
如果特征与目标值是非线性关系,回归线是一条曲线,即 目标值与某个或多个特征之间存在幂函数的关系, 如何预测目标值呢?这就出现了多项式回归;
多项式回归的实现方式很简单,既然我们假设 目标值与 特征存在高次幂的关系,那么我们可以将所有特征 求出幂函数值,作为新的特征添加到特征中,也就是对数据进行升纬
例 : y = a x 2 + b x + c 例: y = ax^2 + bx + c y=ax2+bx+c
假设如上的二次函数模型,特征纬度为1,即 x;我们可以将 x 2 x^2 x2 看作一个新的特征 x 1 = x 2 x_1 = x^2 x1=x2,这样就相当于特征纬度变为2,
y = a x 1 + b x 2 + c y = ax_1 + bx_2 + c y=ax1+bx2+c
舒服了~
然后用多元线性回归 模型来训练,得到各个特征的 θ \theta θ 系数,这样就实现了多项式回归

这里我们 生成一个训练数据集

import matplotlib.pyplot as plt
import numpy as np

X = np.arange(-10,10,.1).reshape((-1,1))
# 目标值与 x 特征之间的关系  y = 0.5x^3 - x^2 + x + 5 + 噪音
y = .5 * X[:,0]**3 - X[:,0]**2 + X[:,0] + 5 + np.random.normal(-50,50,200)
plt.scatter(X,y)

最终绘制出来的是这样,就像《野狼disco》里面的彩虹
在这里插入图片描述
接下来我们使用 sklearn 为我们提供的 Pipeline 将数据特征堆叠、数据归一化、线性回归 组装到一起,就构成了一个 可以训练 多项式回归模型 的函数

  • PolynomialFeatures 用于将特征进行升纬,构造函数传入 degree 表示将特征的 最多几次方添加到特征中
  • StandardScaler 数据归一化,用于统一特征量纲
  • LinearRegression 线性回归
# 将数据样本分为 训练数据集 和 测试数据集
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y)
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

def polynomialFeatures(degree):
    return Pipeline([
        ("poly", PolynomialFeatures(degree=degree)),
        ("scaler", StandardScaler()),
        ("linear_reg", LinearRegression())
    ])

过拟合、欠拟合、泛化能力

我们手动生成的训练数据集中, 我们知道 y 与 x 是存在 最高 三次方的关系
下面,我会分别使用 1次方 、平方、 三次方 以及 三十次方 来尝试进行训练
进而阐述 过拟合 和 欠拟合 现象

# 1次方
poly1 = polynomialFeatures(degree=1)
poly1.fit(X_train, y_train)
y_pre1 = poly1.predict(X_train)
plt.scatter(X,y)
plt.plot(np.sort(X_train[:,0]), y_pre1[np.argsort(X_train[:,0])],color = "red")
plt.title("R_Squared: {}".format(poly1.score(X_test, y_test)), color="red")

在这里插入图片描述
由于使用特征最高 1次方,相当于是简单线性回归来, 所以回归线是一个直线
使用R_Squared 模型准确的评估, 准确度为 0.786 的样子,完全一副人工智障的样子
这就是欠拟合的结果,我们训练数据集中,特征与目标值是最高三次方的关系,但是我们训练的模型是 一次方关系,换句话说 这个模型并不能完整的表达 特征与目标值之间的关系,所以 模型准确度 只有 0.7

下面是 平方的多项式回归模型

poly2 = polynomialFeatures(degree = 2)
poly2.fit(X_train, y_train)
y_pre2 = poly2.predict(X_train)

plt.title("R_Squared: {}".format(poly2.score(X_test, y_test)),color = "red")
plt.scatter(X,y)
plt.plot(np.sort(X_train[:,0]),y_pre2[np.argsort(X_train[:,0])],color = "red")

使用 含有特征平方值的训练数据集 训练的模型,有一点曲线的样子了
But ! 但是 ! However !
R_2 模型准确度评估结果为 0.71 比一次方还要低,从图像来看 又是一个欠拟合的产物
在这里插入图片描述

下面是 最高三次方的训练数据集训练的 多项式回归模型, 这跟我们生成的规则是一致的

poly3 = polynomialFeatures(degree = 3)
poly3.fit(X_train, y_train)
y_pre3 = poly3.predict(X_train)

plt.title("R_Squared: {}".format(poly3.score(X_test, y_test)), color="red")
plt.scatter(X,y)
plt.plot(np.sort(X_train[:,0]), y_pre3[np.argsort(X_train[:,0])],color = "red")

在这里插入图片描述
**excellent! **
训练出来的模型 至少从视觉上 完美的拟合了样本,R_2 模型准确度评估也达到了 0.94

模型误差 = 偏差 + 方差 + 无法避免的误差

由于训练数据集生成过程中 我们加入了 噪音,所以误差是客观存在的

接下来 我们再看一下 过拟合的情况, 这次我们使用 特征最高30次方的值 ,作为新的特征加入训练数据集

poly5 = polynomialFeatures(degree =30)
poly5.fit(X_train, y_train)
y_pre5 = poly5.predict(X_train)

plt.title("R_Squared: {}".format(poly5.score(X_test, y_test)), color="red")
plt.scatter(X,y)
plt.plot(np.sort(X_train[:,0]), y_pre5[np.argsort(X_train[:,0])],color = "red")

在这里插入图片描述
这个回归曲线非常花里胡哨, 弯弯绕绕,好像拟合的非常棒,但是使用测试数据集 进行模型准确度评估 R_2 = -2.17 ,当R_2 模型准确度为 负数时 ,可以理解为模型完全是错的,甚至不如使用 平均值 作为模型进行预估;

泛化能力

我们明明看曲线拟合的还不错,为什么R_2 指标这么低呢,原因就在于 过拟合:对训练样本拟合的很好,但是应用到生产环境,碰到新的样本 预测结果表现的很差,模型把一些无关的 特征 学习到了,这就是过拟合情况,同时也表现出 模型的泛化能力较低,难以将模型泛化到 新的样本上

学习曲线

我们来绘制上面几个模型的学习曲线; 随着训练样本数量增加, 模型对 训练样本预测误差 和 测试样本预测误差的变化趋势,进一步说明 过拟合 ,欠拟合 ,以及泛化能力

下面几张图中 X 轴为 训练样本的数量, Y轴为 MSE(均方误差)用于衡量 预测值与实际值的误差,误差越大,可理解为模型准确度越低;
每幅图有两条线,没别表示 模型对 训练数据集预测的误差 和 泛化到训练数据集中不存在的样本后 预测误差

from sklearn.metrics import mean_squared_error
# 绘制模型学习曲线
def drawLearnLinear(func, X, y):
    X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.3)
    train_mse = np.empty(len(X_train))
    test_mse = np.empty(len(X_train))
    for i in range(len(X_train)):
        func.fit(X_train[:(i+1)], y_train[:(i+1)])
        train_mse[i] = mean_squared_error(y_train[:(i+1)], func.predict(X_train[:(i+1)]))
        test_mse[i] = mean_squared_error(y_test, func.predict(X_test))
    plt.plot(np.arange(len(X_train)), train_mse, label = "train line")
    plt.plot(np.arange(len(X_train)), test_mse, label = "test line")
    plt.axis([0,len(X_train),0, 50000])
    plt.legend()

一次方 的模型 学习曲线(欠拟合)

drawLearnLinear(poly1,X,y)

如下图 随着训练样本数量增加 ,两个误差 最后稳定在 10000多一点,但是两条线间距逐渐减小,说明泛化能力还可以
在这里插入图片描述

三次方的模型 学习曲线

drawLearnLinear(poly3,X,y)

这幅图简直完美,

  1. 随着训练样本增加,两条线几乎合并,模型泛化能力很好,说明模型在训练样本训练后泛化到 新的样本上,误差几乎一致
  2. 最终误差稳定在3000 左右的样子,相比上一幅图小了很多,相比较之下 也说明上面的模型 欠拟合

在这里插入图片描述

30次方的模型学习曲线

drawLearnLinear(poly5,X,y)
  1. 训练样本 和 测试样本 之间间距很大 并且 测试样本误差非常不稳定,大出天际,过拟合,泛化能力较低
    在这里插入图片描述

在实际应用过程中,我们大都是在解决过拟合情况,我们使用训练数据集训练模型,然后发现 拟合的不错,即使发生过拟合也不自知,在高纬度的样本空间中,可是很难以进行可视化;所以接下来我们讨论如何解决过拟合

我们打印 上面 几个模型 ,学习到的 θ \theta θ 参数

poly1.get_params()['linear_reg'].coef_
array([  0.        , 186.11946548])
poly2.get_params()['linear_reg'].coef_
array([  0.        , 163.6013378 , -50.05769662])
poly3.get_params()['linear_reg'].coef_
array([  0.        ,   2.00832969, -37.03488194, 208.61357956])
poly5.get_params()['linear_reg'].coef_
array([ 3.60460115e+12, -7.50492893e+01,  4.02625575e+02,  7.50064206e+03,
       -5.31983387e+04, -1.89716199e+05,  1.86114685e+06,  1.97519240e+06,
       -3.09333497e+07, -7.12811683e+06,  2.96235084e+08, -3.19140561e+07,
       -1.80711808e+09,  4.60268720e+08,  7.44470660e+09, -2.33671288e+09,
       -2.14435003e+10,  7.02475143e+09,  4.39978121e+10, -1.38712963e+10,
       -6.46641554e+10,  1.85250937e+10,  6.75581331e+10, -1.66255368e+10,
       -4.89684824e+10,  9.62439487e+09,  2.34009853e+10, -3.25078340e+09,
       -6.62797198e+09,  4.87070189e+08,  8.42481030e+08])

可以发现 过拟合的模型,学习到的特征系数 绝对值都非常大,那么我们是否通过限制 θ \theta θ 的大小,来避免过拟合情况发生呢

答案是肯定的,我们可以在最小化损失函数过程中,最小化 θ \theta θ ,在多元线性回归的损失函数后面添加一项
α 1 2 ∑ i = 1 n θ i 2 \alpha \frac 1 2 \displaystyle \sum_{i=1}^n \theta_i^2 α21i=1nθi2
或者
α 1 2 ∑ i = 1 n ∣ θ i ∣ \alpha \frac 1 2 \displaystyle \sum_{i=1}^n |\theta_i| α21i=1nθi

然后最小化损失函数, α \alpha α 也是新增的超参数,在我理解是用来控制 θ \theta θ 在损失函数中的影响比重

两种不同的回归模型损失函数如下:

在这里插入图片描述

尝试使用Ridge回归、 LASSO回归 解决过拟合

Ridge 回归

from sklearn.linear_model import Ridge
def ridgeFeatures(degree,alpha):
    return Pipeline([
        ("poly", PolynomialFeatures(degree=degree)),
        ("scaler", StandardScaler()),
        ("linear_reg", Ridge(alpha = alpha))
    ])

直接使用 30次方, 可能存在过拟合情况 来看一下Ridge回归的威力

ridge = ridgeFeatures(30,1)

ridge.fit(X_train, y_train)

print("模型预测准确度:",ridge.score(X_test,y_test))

模型预测准确度: 0.9557567126123063

再次绘制学习曲线

drawLearnLinear(ridge, X, y)

在这里插入图片描述
神奇的事情发生了,R_2 模型准确度达到了0.95,并且误差和泛化能力都不错,这可是包含各个特征30次方的训练数据集!

LASSO回归

from sklearn.linear_model import Lasso

def lassoFeatures(degree,alpha):
    return Pipeline([
        ("poly", PolynomialFeatures(degree=degree)),
        ("scaler", StandardScaler()),
        ("linear_reg", Lasso(alpha = alpha))
    ])

使用可能存在过拟合情况的超参数

lasso = lassoFeatures(30, 10)
lasso.fit(X_train,y_train)
print("模型预测准确度:",lasso.score(X_test,y_test))

模型预测准确度: 0.9447394073618249

绘制学习曲线

drawLearnLinear(lasso, X, y)

在这里插入图片描述
perfect!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值