【笔记】过拟合和欠拟合以及为什么要对分为训练数据集和测试数据集

过拟合和欠拟合以及为什么要对分为训练数据集和测试数据集

过拟合和欠拟合

有了多项式回归以后,就可以比较轻松地用线性回归来求解非线性的问题了,不过过于使用可能会导致过拟合和欠拟合

先使用实际的例子来说明过拟合和欠拟合

(在notebook中)

加载好包,创建好虚假的数据集x和y,设置随机种子666,然后绘制出图像

  import numpy as np
  import matplotlib.pyplot as plt
  np.random.seed(666)
  x = np.random.uniform(-3.0,3.0,size=100)
  X = x.reshape(-1,1)
  y = 0.5 * x**2 + x + 2 + np.random.normal(0,1,size=100)
  plt.scatter(x,y)

图像如下

之前使用线性回归的时候可以发现是不好的,详情见上篇内容

要注意,直接使用线性回归和使用了升维以后在线性回归这两个方程的计算是不同的,因此衡量好坏可以使用均方误差的方法

使用均方误差来衡量

具体操作

加载上mean_squared_error这个方式,使用均方误差来说,需要知道对于这个模型,其对于X预测的结果是怎样的,然后再使用mean_squared_error,将y的真值以及预测的y传入

  from sklearn.metrics import mean_squared_error

  y_predict = lin_reg.predict(X)
  mean_squared_error(y,y_predict)

结果如下(均方误差为3.07左右)

使用多项式回归

使用pipeline的应用,设立一个PolynomialRegression的函数,就是对之前的管道进行了包装,传入degree后,返回pipeline,其中就是多项式回归的三步

  from sklearn.pipeline import Pipeline
  from sklearn.preprocessing import StandardScaler
  from sklearn.preprocessing import PolynomialFeatures

  def PolynomialRegression(degree):
      return Pipeline([
          ("poly",PolynomialFeatures(degree=degree)),
          ("std_scaler",StandardScaler()),
          ("lin_reg",LinearRegression())
      ])

首先创建一个多项式回归的对象,相应的其中degree为2,然后进行fit的操作

  poly2_reg = PolynomialRegression(degree=2)
  poly2_reg.fit(X,y)

结果为

这样就可以进行预测了,在预测结束以后使用均方误差的方法得到均方误差

  y2_predict = poly2_reg.predict(X)
  mean_squared_error(y,y2_predict)

结果为(均方误差为1.098左右,显然比线性回归要小)

绘制出图像

  plt.scatter(x,y)
  plt.plot(np.sort(x),y2_predict[np.argsort(x)],color='r')

图像为(可以发现与之前的是一致的)

试一下传入更大的degree来看一下均方误差

  poly100_reg = PolynomialRegression(degree=100)
  poly100_reg.fit(X,y)

  y100_predict = poly100_reg.predict(X)
  mean_squared_error(y,y100_predict)

情况如下(可知比degree为2要小不少)

绘制一下图像

  plt.scatter(x,y)
  plt.plot(np.sort(x),y100_predict[np.argsort(x)],color='r')

图像为(抖得挺厉害)

这个曲线只是原有的点之间对应的预测值连接出来的结果,不过很多地方可能没有数据点,所以连接的结果和原来的曲线是不一样的,我们还原出原本的曲线

设置一个样本数据及x_plot,使其在-3到3之间均匀的取一百个值并将其变为100行1列的矩阵,然后将这个新的样本集传进去得到y_plot,然后对其进行绘制(设置好范围)

  X_plot = np.linspace(-3,3,100).reshape(100,1)
  y_plot = poly100_reg.predict(X_plot)

  plt.scatter(x,y)
  plt.plot(X_plot[:,0],y_plot,color='r')
  plt.axis([-3,3,-1,10])

图像如下

由于数据样本是均匀取值的,所以不会出现两点之间间隔太大,这样,就得出了真正的曲线

很显然,degree传入的越高,结果越好,毕竟只要找到让所有的点都在的曲线即可,只是这样会使得degree特别的高

那么问题来了

这个结果从均方误差的角度来看,是更好的,但是这真的是一个更好的反映样本走势的曲线吗?虽然使用了非常高维的数据,使得所有的点获得的误差更小了,但是这个曲线不是需要的,其为了拟合所有的给定的样本点,变得太复杂了,这种就称其为过拟合,机器学习一般解决的是这种

直接使用一根直线的方式很显然没有很好的反映出原始数据的样本特征,其太过简单了,这种就可以称为欠拟合

通过观察这个曲线可以知道,其称为过拟合是因为虽然得到了曲线且使用这条曲线来预测的话相应的误差就变小了,但是如果有一个新的样本的话,假设一个样本x为2.4,那么根据这个曲线预测出的值可能y为0.4左右,可以发现,这个预测的结果和之前的样本点不在一个趋势上,很容易将这个预测值作为错误值

也就是说,在过拟合的情况下,虽然将这些样本点拟合的很好,但是来了新的样本点的时候,对新的样本点就没法很好的预测了,可以说,这条曲线的泛化能力是非常弱的(泛化能力,可以看作为由此及彼的能力),得出这条曲线是为了更好的预测,而不是为了追求原先数据的拟合误差小,我们真正需要的使这个模型的泛化能力好

训练数据集与测试数据集分离的意义

那么要使这个模型的泛化能力好应该怎么做呢?

其实就是使用训练测试数据集的分离,将原本的数据分为训练数据集和测试数据集,而获得模型只使用训练数据集来获得,如果使用训练数据集获得的模型对测试数据集的模型也有很不错的预测结果的话,就可以说这个魔性的泛化能力强,反之,称其为泛化能力弱,这就是测试数据集的更大的意义

具体实现提现其意义

(在notebook中)

首先使用下面的代码将之前的情况布置出来

  import numpy as np
  import matplotlib.pyplot as plt

  np.random.seed(666)
  x = np.random.uniform(-3.0,3.0,size=100)
  X = x.reshape(-1,1)
  y = 0.5 * x**2 + x + 2 + np.random.normal(0,1,size=100)

  from sklearn.pipeline import Pipeline
  from sklearn.preprocessing import StandardScaler
  from sklearn.preprocessing import PolynomialFeatures
  from sklearn.linear_model import LinearRegression

  def PolynomialRegression(degree):
      return Pipeline([
          ("poly",PolynomialFeatures(degree=degree)),
          ("std_scaler",StandardScaler()),
          ("lin_reg",LinearRegression())
      ])

  poly100_reg = PolynomialRegression(degree=100)
  poly100_reg.fit(X,y)

  X_plot = np.linspace(-3,3,100).reshape(100,1)
  y_plot = poly100_reg.predict(X_plot)

  plt.scatter(x,y)
  plt.plot(X_plot[:,0],y_plot,color='r')
  plt.axis([-3,3,-1,10])

可以得到图像:

首先使用sklearn中的train_test_split来将数据集进行分割,种子为666

  from sklearn.model_selection import train_test_split
  X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=666)

之后操作与之前大致相同

首先先看一下对于线性回归来说,先实例化一个对象,然后fit训练数据集,在进行对x_test的预测以后计算测试数据集和预测结果的均方误差

  from sklearn.metrics import mean_squared_error

  lin_reg = LinearRegression()
  lin_reg.fit(X_train,y_train)
  y_predict = lin_reg.predict(X_test)
  mean_squared_error(y_test,y_predict)

结果为(对于线性回归来说,误差为2.21)

使用多项式回归的方式,和之前的操作一样

  poly2_reg = PolynomialRegression(degree=2)
  poly2_reg.fit(X_train,y_train)
  y2_predict = poly2_reg.predict(X_test)
  mean_squared_error(y_test,y2_predict)

结果为0.8左右(可以得出,在这种情况下,使用多项式回归的模型得到的结果的泛化能力比线性回归的结果是要好的)

设置成degree为100

  poly100_reg = PolynomialRegression(degree=100)
  poly100_reg.fit(X_train,y_train)
  y100_predict = poly100_reg.predict(X_test)
  mean_squared_error(y_test,y100_predict)

结果如下

这个误差直接起飞,不过和上面的图像其实是吻合的

虽然在degree为100的时候,其对于训练数据集的拟合是非常好的,但是面对新的数据的时候,其预测结果是相当差的,所以说这个模型对于预测来讲是十分没用的

上面的实验实际上就是在测试模型的复杂度,对于多项式回归来说,阶数越高,模型越复杂,对于机器算法来说,对于训练数据集来说,模型复杂度越高,模型的准确率越好,模型越复杂,对数据的拟合就越好,因此准确率也就高了,对于测试数据集来说,随着模型负责度的提升,模型准确率会进行先升后降,即从欠拟合到合适再到过拟合的过程
(横轴为模型复杂度,纵轴为模型准确率)

那么就可以知道过拟合和欠拟合的大致意思了

欠拟合 underfitting

欠拟合是指模型的拟合程度不高,数据距离拟合曲线大部分较远,或说模型没有很好地捕捉到数据特征,不能够很好地拟合数据,即算法训练的模型不能完整的表述数据关系

过拟合 overfitting

过拟合是指为了得到追求极高的拟合而严格过头的情况,即算法所训练的模型过多的表达了数据间的噪音关系,将这些噪音也作为特征进行了训练

可以举一个简单的例子,在机器学习的时候,如果说根据模型,认为只要带眼睛,那就是狗,这很明显就是欠拟合模型,太简单了,但是也不能说,具备了狗的特征以后,只有有金色毛发的,才算狗,这就是过拟合了,好家伙直接给其他颜色的狗开除狗籍,这肯定是不行的

过拟合和欠拟合是机器学习中一直需要注意和解决的重点,对于模型的目标,就变成找到泛化能力最好的地方,找到合适的模型复杂度,即找到模型对测试数据模型的最好的参数

posted @ 2021-01-21 16:54  DbWong_0918  阅读(1094)  评论(0编辑  收藏  举报