【笔记】多项式回归的思想以及在sklearn中使用多项式回归和pipeline

多项式回归以及在sklearn中使用多项式回归和pipeline

多项式回归

线性回归法有一个很大的局限性,就是假设数据背后是存在线性关系的,但是实际上,具有线性关系的数据集是相对来说比较少的,更多时候,数据之间是具有的非线性的关系,那么我们想要用线性回归法来对非线性的数据进行处理应该怎么办呢,我们可以使用多项式回归的手段来改进线性回归法,使线性回归法也可以对非线性的数据进行处理,并进行预测

通过多项式回归可以引出一个很重要的概念,即模型泛化的问题

什么是多项式回归呢?

对于线性回归来说,对于数据,我们想找到一条直线,使其尽可能的拟合这些数据,若只有一个特征的话,我们可以称直线为y=ax+b(x为样本特征,a和b为参数),但是对于很多的数据来说,虽然可以使用一条直线来拟合数据,但是其分布很多时候是具有更强的非线性的关系,也就是说,使用二次曲线来拟合这些数据的话效果会更好,如果也是只有一个特征的话,那么方程就可以写成y=ax²+bx+c

虽然称其为一个特征的二次方程,但是可以从另一个方向来理解这个方程,如果将X²看成是一个特征,X看成另一个特征,这就将其看成是含有两个特征的数据集,多了一个X²的特征,从这个方向来看的话,这个式子依然是一个线性回归的式子,从X的角度来看,就是一个非线性的方程,这样的方式就称为多项式回归

相当于为样本多添加了几个特征,这些特征是原先样本的多项式项(像是X²就是对X进行了平方),增加了这些特征以后就可以使用线性回归的思路,来更好的拟合原来的数据,本质上就是,求出了原来的特征而言的非线性的曲线,即为了更好地拟合数据进行了升维

需要注意的是,思路方面,对数据集的操作里,PCA是对数据集进行降维处理,而多项式回归是让数据集进行升维,在升维以后可以更好地拟合高维的数据,这两种要看情况使用

实现

(在notebook中)

仍然是加载好需要的包,接着生成一个随机的数据作为样本数据,从-3到3之间进行100个随机的取值,接着reshape成一个二维数组,设置y为0.5乘上x的平方加上x再加上2以后添加一些噪点,可视化一下关系图像来看一下数据集

  import numpy as np
  import matplotlib.pyplot as plt

  x = np.random.uniform(-3,3,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)

图像如下

用线性回归的方式

首先引用LinearRegression这个类,然后实例化以后进行fit,fit传入X和y

  from sklearn.linear_model import LinearRegression

  lin_reg = LinearRegression()
  lin_reg.fit(X,y)

结果如下

拟合以后,使用predict方法将X传入,得到预测结果,并对其进行绘制

  y_predict = lin_reg.predict(X)

  plt.scatter(x,y)
  plt.plot(x,y_predict,color='r')

图像如下

从图像可以发现,使用直线来拟合有弧度的曲线,效果不是特别好,那么我们添加一个特征来解决这个情况

对X中的每一个数据进行平方,X²其本身就是一个新的特征,使用(X**2).shape,可以看出其是一个100行1列的矩阵

用hstack的方法将原来的X和新的X²合在一起组成一组新的含有100行2列的数据集

  X2 = np.hstack([X,X**2])
  X2.shape

结果如下

现在就可以使用新的数据集进行训练,操作同上,同时得出预测结果以后将新的预测结果绘制出来,需要注意的是,如果还是使用plt.plot(x,y_predict2,color='r')来绘制的话,生成的图是乱的(因为x是没有顺序的),如果想生成平滑的曲线的话,就要对x进行从小到大的排序才可以,对于预测结果来说,也要对排序以后的x进行预测才可以

  lin_reg2 = LinearRegression()
  lin_reg2.fit(X2,y)
  y_predict2 = lin_reg2.predict(X2)

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

图像如下

显然,这条曲线对数据集的拟合是比直线更好的

使用lin_reg2.coef_看一下系数

同时使用lin_reg2.intercept_来看一下截距

可以发现,这个和之前假设的生成数据大致上是拟合的,因为先前设置了噪音,所以会有偏差

这就是多项式回归的思路,其关键在于为原来的数据样本添加新的特征,而得到新的特征的方式是原有的特征的多项式组合,使用这种方式,我们就可以解决一些非线性问题

在sklearn中使用多项式回归和pipeline

(在notebook中,和上面的不是一个文件)

首先加载好需要的包,再设置好的虚拟的数据集,之后引用PolynomialFeatures类,使用方法同样的,先进行实例化,传入参数degree,其表示为原来的数据集添加的最高的幂,这里设置为2,这就初始化好了,然后fit一下X,之后调用poly.transform这个方式,将其转换成多项式的特征

  from sklearn.preprocessing import PolynomialFeatures

  poly = PolynomialFeatures(degree=2)
  poly.fit(X)
  X2 = poly.transform(X)

我们使用X2.shape可以看到这是一个100*3的矩阵

我们看一下前5行的数据

  X2[:5,:]

结果如下(第一列的1可以看作为x的0次方,第2列就是原来的样本特征,第3列就是x的平方的特征,以此类推)

验证一下是不是,将x的前5行也输出出来X[:5,:],可以发现和x2的第2列是一样的

之后的操作同上,引用LinearRegression这个类,然后实例化再进行fit,拟合后,使用predict方法得到预测结果,并对其进行绘制

  from sklearn.linear_model import LinearRegression

  lin_reg2 = LinearRegression()
  lin_reg2.fit(X2,y)
  y_predict2 = lin_reg2.predict(X2)

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

图像如下

同样的,看一下系数和截距

关于PolynomialFeatures的运算逻辑

试一下设置x为两个特征,设置成一到十的数字分成两列

  X = np.arange(1,11).reshape(-1,2)
  X.shape

结果如下

其内容X如下

现在试一下PolynomialFeatures,首先进行操作,将其转换成最多包含二次幂的数据集

  poly = PolynomialFeatures(degree=2)
  poly.fit(X)
  X2 = poly.transform(X)
  X2.shape

结果如下(其为五行六列的数据集)

其中X2内的数据为

从图中可以看出来,第一列仍然是0次幂,第二列和第三列也是原来的,第四列为原来的第一列的平方,第六列是原来的第二列的平方,那么第五列变成了原来两列特征相乘的结果,这里就得注意,原来有二次幂的特征,再生成二次幂的话就会产生三列,为第一列的平方,第一列和第二列的乘积,第二列的平方

可想而知,如果degree为3的话,就更加复杂了,其有十列数据,为什么呢,因为这就相当于是,0次方,1次方,2次方,3次方的全部的集合,且包含相互的乘积,设第一列为x1,第二列为x2,则其中就有1,x1,x2,x2的平方,x1的平方,x1乘x2,x1的三次方,x2的三次方,x1的平方乘上x2,x2的平方乘上x1

那么就说明PolynomialFeatures的degree传入的是i的话,那么其将自动生成不小于i的相应的所有的多项式的项,这就涉及到了所有的多项式的特征

在具体实现的时候如果使用sklearn的话,由于sklearn中没有多项式回归这个类,那么使用pipeline创建一个多项式回归的类就可以方便使用这种多项式回归的方式

想要实现多项式回归的话,先要将原先的数据升维成多项式的样本的数据,但是如果degree非常的大的话,样本之间的差距也会特别的大,像是线性回归的时候用梯度下降法,如果数据不均衡的话,搜索会非常的慢,需要进行数据归一化,然后在线性回归,需要进行三步,而使用pipeline的话,可以将这三步合在一起

具体操作,同样的使用虚拟的测试用例

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

然后引用pipeline这个类,进行实例化,对pipeline进行构造,其中的列表就是对应的每一个步骤的对应的类,第一步进行多项式的过程,第二步进行数据归一化,第三步就是进行线性回归,这就创建了一个管道

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

  poly_reg = Pipeline([
      ("poly",PolynomialFeatures(degree=2)),
      ("std_scaler",StandardScaler()),
      ("lin_reg",LinearRegression())
  ])

使用方式与其他的封装的算法是一样的,调用fit,将原始的x和y,其过程很智能,再传入以后进行预测,绘制出图像

  poly_reg.fit(X,y)
  y_predict = poly_reg.predict(X)

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

图像如下

以上

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