线性回归 - PolynomialFeatures(八)

705 阅读20分钟

根据菜菜的课程进行整理,方便记忆理解

代码位置如下:

多项式回归PolynomialFeatures

多项式对数据做了什么

除了分箱之外,另一种更普遍的用于解决”线性回归只能处理线性数据“问题的手段,就是使用多项式回归对线性回归进行改进。这样的手法是机器学习研究者们从支持向量机中获得的:支持向量机通过升维可以将非线性可分数据转化为线性可分,然后使用核函数在低维空间中进行计算,这是一种“高维呈现,低维解释”的思维。那我们为什么不能让线性回归使用类似于升维的转换,将数据由非线性转换为线性,从而为线性回归赋予处理非线性数据的能力呢?当然可以。

image.png

接下来,我们就来看看线性模型中的升维工具:多项式变化。这是一种通过增加自变量上的次数,而将数据映射到高维空间的方法,只要我们设定一个自变量上的次数(大于1),就可以相应地获得数据投影在高次方的空间中的结果。这种方法可以非常容易地通过sklearn中的类PolynomialFeatures来实现。我们先来简单看看这个类是如何使用的。

class sklearn.preprocessing.PolynomialFeatures (degree=2, interaction_only=False, include_bias=True)

参数含义
degree多项式中的次数,默认为2
interaction_only布尔值是否只产生交互项,默认为False
include_bias布尔值,是否产出与截距项相乘的,默认True
from sklearn.preprocessing import PolynomialFeatures
import numpy as np

#如果原始数据是一维的
X = np.arange(1,4).reshape(-1,1)
X

"""
array([[1],
       [2],
       [3]])
"""

#二次多项式,参数degree控制多项式的次方
poly = PolynomialFeatures(degree=2)

#接口transform直接调用
X_ = poly.fit_transform(X)
X_
"""
array([[1., 1., 1.],
       [1., 2., 4.],
       [1., 3., 9.]])
"""
X_.shape
# (3, 3)

不难注意到,多项式变化后数据看起来不太一样了:首先,数据的特征(维度)增加了,这正符合我们希望的将数据转换到高维空间的愿望。其次,维度的增加是有一定的规律的。不难发现,如果我们本来的特征矩阵中只有一个特征x,而转换后我们得到:

image.png

这个规律在转换为二次多项式的时候同样适用。原本,我们的模型应该是形似y=ax+by = ax + b的结构,而转换后我们的特征变化导致了模型的变化。根据我们在支持向量机中的经验,现在这个被投影到更高维空间中的数据在某个角度上看起来已经是一条直线了,于是我们可以继续使用线性回归来进行拟合。线性回归是会对每个特征拟合出权重的,所以当我们拟合高维数据的时候,我们会得到下面的模型:

image.png

由此推断,假设多项式转化的次数是n,则数据会被转化成形如:

image.png

而拟合出的方程也可以被改写成:

image.png

这就是大家会在大多数数学和机器学习教材中会看到的“多项式回归”的表达式。这个过程看起来非常简单,只不过是将原始的x上的次方增加,并且为这些次方项都加上权重ww,然后增加一列所有次方为0的列作为截距乘数的x0x_0,参数include_bias就是用来控制x0x_0的生成的。

#三次多项式
PolynomialFeatures(degree=3).fit_transform(X)
"""
array([[ 1.,  1.,  1.,  1.],
       [ 1.,  2.,  4.,  8.],
       [ 1.,  3.,  9., 27.]])
"""

#三次多项式,不带与截距项相乘的x0
PolynomialFeatures(degree=3,include_bias=False).fit_transform(X)
"""
array([[ 1.,  1.,  1.],
       [ 2.,  4.,  8.],
       [ 3.,  9., 27.]])
"""

#为什么我们会希望不生成与截距相乘的x0呢?
#对于多项式回归来说,我们已经为线性回归准备好了x0,但是线性回归并不知道
xxx = PolynomialFeatures(degree=3).fit_transform(X)
xxx.shape
# (3, 4)

rnd = np.random.RandomState(42) #设置随机数种子
y = rnd.randn(3)

y
# array([ 0.49671415, -0.1382643 ,  0.64768854])

from sklearn.preprocessing import PolynomialFeatures as PF
from sklearn.linear_model import LinearRegression
#生成了多少个系数?
LinearRegression().fit(xxx,y).coef_
# array([ 3.08086889e-15, -3.51045297e-01, -6.06987134e-01,  2.19575463e-01])

#查看截距
LinearRegression().fit(xxx,y).intercept_
# 1.2351711202036884

#发现问题了吗?线性回归并没有把多项式生成的x0当作是截距项
#所以我们可以选择:关闭多项式回归中的include_bias
#也可以选择:关闭线性回归中的fit_intercept

#生成了多少个系数?
LinearRegression(fit_intercept=False).fit(xxx,y).coef_
# array([ 1.00596411,  0.06916756, -0.83619415,  0.25777663])

#查看截距
LinearRegression(fit_intercept=False).fit(xxx,y).intercept_
# 0.0

不过,这只是一维状况的表达,大多数时候我们的原始特征矩阵不可能会是一维的,至少也是二维以上,很多时候还可能存在上千个特征或者维度。现在我们来看看原始特征矩阵是二维的状况:

X = np.arange(6).reshape(3, 2)
X
"""
array([[0, 1],
       [2, 3],
       [4, 5]])

"""

#尝试二次多项式
PolynomialFeatures(degree=2).fit_transform(X)
"""
array([[ 1.,  0.,  1.,  0.,  0.,  1.],
       [ 1.,  2.,  3.,  4.,  6.,  9.],
       [ 1.,  4.,  5., 16., 20., 25.]])
"""

很明显,上面一维的转换公式已经不适用了,但如果我们仔细看,是可以看出这样的规律的:

image.png

当原始特征为二维的时候,多项式的二次变化突然将特征增加到了六维,其中一维是常量(也就是截距)。当我们继续适用线性回归去拟合的时候,我们会得到的方程如下:

image.png

这个时候大家可能就会感觉到比较困惑了,怎么会出现这样的变化?如果想要总结这个规律,可以继续来尝试三次多项式:

#尝试三次多项式
PolynomialFeatures(degree=3).fit_transform(X)
"""
array([[  1.,   0.,   1.,   0.,   0.,   1.,   0.,   0.,   0.,   1.],
       [  1.,   2.,   3.,   4.,   6.,   9.,   8.,  12.,  18.,  27.],
       [  1.,   4.,   5.,  16.,  20.,  25.,  64.,  80., 100., 125.]])
"""

很明显,我们可以看出这次生成的数据有这样的规律:

image.png

不难发现:当我们进行多项式转换的时候,多项式会产出到最高次数为止的所有低高次项。比如如果我们规定多项式的次数为2,多项式就会产出所有次数为1和次数为2的项反馈给我们,相应的如果我们规定多项式的次数为n,则多项式会产出所有从次数为1到次数为n的项。注意,x1x2x_1x_2x12x_1^2一样都是二次项,一个自变量的平方其实也就相当于是x1x2x_1x_2,所以在三次多项式中x12x2x_1^2x_2就是三次项。

在多项式回归中,我们可以规定是否产生平方或者立方项,其实如果我们只要求高次项的话, x1x2x_1x_2会是一个比x12x_1^2更好的高次项,因为x1x2x_1x_2x1x_1之间的共线性会比x12x_1^2x1x_1之间的共线性好那么一点点(只是一点点),而我们多项式转化之后是需要使用线性回归模型来进行拟合的,就算机器学习中不是那么在意数据上的基本假设,但是太过分的共线性还是会影响到模型的拟合。因此sklearn中存在着控制是否要生成平方和立方项的参数interaction_only,默认为False,以减少共线性。来看这个参数是如何工作的:

PolynomialFeatures(degree=2).fit_transform(X)
"""
array([[ 1.,  0.,  1.,  0.,  0.,  1.],
       [ 1.,  2.,  3.,  4.,  6.,  9.],
       [ 1.,  4.,  5., 16., 20., 25.]])
"""

PolynomialFeatures(degree=2,interaction_only=True).fit_transform(X)
#对比之下,当interaction_only为True的时候,只生成交互项
"""
array([[ 1.,  0.,  1.,  0.],
       [ 1.,  2.,  3.,  6.],
       [ 1.,  4.,  5., 20.]])
"""

从之前的许多次尝试中我们可以看出,随着多项式的次数逐渐变高,特征矩阵会被转化得越来越复杂。不仅是次数,当特征矩阵中的维度数(特征数)增加的时候,多项式同样会变得更加复杂:

#更高维度的原始特征矩阵
X = np.arange(20).reshape(2, 10)
X
"""
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]])
"""

PolynomialFeatures(degree=2).fit_transform(X).shape
# (2, 66)

PolynomialFeatures(degree=3).fit_transform(X).shape
# (2, 286)

X_ = PolynomialFeatures(degree=20).fit_transform(X)
X_.shape
# (2, 30045015)

如此,多项式变化对于数据会有怎样的影响就一目了然了:随着原特征矩阵的维度上升,随着我们规定的最高次数的上升,数据会变得越来越复杂,维度越来越多,并且这种维度的增加并不能用太简单的数学公式表达出来。因此,多项式回归没有固定的模型表达式,多项式回归的模型最终长什么样子是由数据和最高次数决定的,因此我们无法断言说某个数学表达式"就是多项式回归的数学表达",因此要求解多项式回归不是一件容易的事儿,感兴趣的大家可以自己去尝试看看用最小二乘法求解多项式回归。接下来,我们就来看看多项式回归的根本作用:处理非线性问题。

多项式回归处理非线性问题

from sklearn.preprocessing import PolynomialFeatures as PF
from sklearn.linear_model import LinearRegression
import numpy as np

rnd = np.random.RandomState(42) #设置随机数种子
X = rnd.uniform(-3, 3, size=100)
y = np.sin(X) + rnd.normal(size=len(X)) / 3

#将X升维,准备好放入sklearn中
X = X.reshape(-1,1)

#创建测试数据,均匀分布在训练集X的取值范围内的一千个点
line = np.linspace(-3, 3, 1000, endpoint=False).reshape(-1, 1)

#原始特征矩阵的拟合结果
LinearR = LinearRegression().fit(X, y)
#对训练数据的拟合
LinearR.score(X,y)
# 0.5361526059318595

#对测试数据的拟合
LinearR.score(line,np.sin(line))
# 0.6800102369793312

#多项式拟合,设定高次项
d=5

#进行高次项转换
poly = PF(degree=d)
X_ = poly.fit_transform(X)
line_ = poly.transform(line)

#训练数据的拟合
LinearR_ = LinearRegression().fit(X_, y)
LinearR_.score(X_,y)
# 0.8561679370344799

#测试数据的拟合
LinearR_.score(line_,np.sin(line))
# 0.9868904451787956

如果我们将这个过程可视化:

import matplotlib.pyplot as plt

d=5
#和上面展示一致的建模流程
LinearR = LinearRegression().fit(X, y)
X_ = PF(degree=d).fit_transform(X)
LinearR_ = LinearRegression().fit(X_, y)
line = np.linspace(-3, 3, 1000, endpoint=False).reshape(-1, 1)
line_ = PF(degree=d).fit_transform(line)

#放置画布
fig, ax1 = plt.subplots(1)

#将测试数据带入predict接口,获得模型的拟合效果并进行绘制
ax1.plot(line, LinearR.predict(line), linewidth=2, color='green'
         ,label="linear regression")
ax1.plot(line, LinearR_.predict(line_), linewidth=2, color='red'
         ,label="Polynomial regression")

#将原数据上的拟合绘制在图像上
ax1.plot(X[:, 0], y, 'o', c='k')

#其他图形选项
ax1.legend(loc="best")
ax1.set_ylabel("Regression output")
ax1.set_xlabel("Input feature")
ax1.set_title("Linear Regression ordinary vs poly")
plt.tight_layout()
plt.show()

#来一起鼓掌,感叹多项式回归的神奇

#随后可以试试看较低和较高的次方会发生什么变化
#d=2
#d=20

image.png

从这里大家可以看出,多项式回归能够较好地拟合非线性数据,还不容易发生过拟合,可以说是保留了线性回归作为线性模型所带的“不容易过拟合”和“计算快速”的性质,同时又实现了优秀地拟合非线性数据。到了这里,相信大家对于多项式回归的效果已经不再怀疑了。多项式回归非常迷人也非常神奇,因此一直以来都有各种各样围绕着多项式回归进行的讨论。

多项式回归的可解释性

线性回归是一个具有高解释性的模型,它能够对每个特征拟合出参数以帮助我们理解每个特征对于标签的作用。当我们进行了多项式转换后,尽管我们还是形成形如线性回归的方程,但随着数据维度和多项式次数的上升,方程也变得异常复杂,我们可能无法一眼看出增维后的特征是由之前的什么特征组成的(之前我们都是肉眼看肉眼判断)。不过,多项式回归的可解释性依然是存在的,我们可以使用接口get_feature_names来调用生成的新特征矩阵的各个特征上的名称,以便帮助我们解释模型。来看下面的例子:

import numpy as np
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression

X = np.arange(9).reshape(3, 3)
X
"""
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
"""

poly = PolynomialFeatures(degree=5).fit(X)
#重要接口get_feature_names
poly.get_feature_names()

"""
['1',
 'x0',
 'x1',
 'x2',
 'x0^2',
 'x0 x1',
 'x0 x2',
 'x1^2',
 'x1 x2',
 'x2^2',
 'x0^3',
 'x0^2 x1',
 'x0^2 x2',
 'x0 x1^2',
 'x0 x1 x2',
 'x0 x2^2',
 'x1^3',
 'x1^2 x2',
 'x1 x2^2',
 'x2^3',
 'x0^4',
 'x0^3 x1',
 'x0^3 x2',
 'x0^2 x1^2',
 'x0^2 x1 x2',
 'x0^2 x2^2',
 'x0 x1^3',
 'x0 x1^2 x2',
 'x0 x1 x2^2',
 'x0 x2^3',
 'x1^4',
 'x1^3 x2',
 'x1^2 x2^2',
 'x1 x2^3',
 'x2^4',
 'x0^5',
 'x0^4 x1',
 'x0^4 x2',
 'x0^3 x1^2',
 'x0^3 x1 x2',
 'x0^3 x2^2',
 'x0^2 x1^3',
 'x0^2 x1^2 x2',
 'x0^2 x1 x2^2',
 'x0^2 x2^3',
 'x0 x1^4',
 'x0 x1^3 x2',
 'x0 x1^2 x2^2',
 'x0 x1 x2^3',
 'x0 x2^4',
 'x1^5',
 'x1^4 x2',
 'x1^3 x2^2',
 'x1^2 x2^3',
 'x1 x2^4',
 'x2^5']
"""

使用加利佛尼亚房价数据集给大家作为例子,当我们有标签名称的时候,可以直接在接口get_feature_names()中输入标签名称来查看新特征究竟是由原特征矩阵中的什么特征组成的

from sklearn.datasets import fetch_california_housing as fch
import pandas as pd

housevalue = fch()
X = pd.DataFrame(housevalue.data)
y = housevalue.target
housevalue.feature_names
"""
['MedInc',
 'HouseAge',
 'AveRooms',
 'AveBedrms',
 'Population',
 'AveOccup',
 'Latitude',
 'Longitude']
"""

X.columns = ["住户收入中位数","房屋使用年代中位数","平均房间数目"
            ,"平均卧室数目","街区人口","平均入住率","街区的纬度","街区的经度"]
X.head()

image.png

poly = PolynomialFeatures(degree=4).fit(X,y)
poly.get_feature_names(X.columns)
"""
['1',
 '住户收入中位数',
 '房屋使用年代中位数',
 '平均房间数目',
 '平均卧室数目',
 '街区人口',
 '平均入住率',
 '街区的纬度',
 '街区的经度',
 '住户收入中位数^2',
 '住户收入中位数 房屋使用年代中位数',
 '住户收入中位数 平均房间数目',
 '住户收入中位数 平均卧室数目',
 '住户收入中位数 街区人口',
 '住户收入中位数 平均入住率',
 '住户收入中位数 街区的纬度',
 '住户收入中位数 街区的经度',
 '房屋使用年代中位数^2',
 …………
 '街区人口^4',
 '街区人口^3 平均入住率',
 '街区人口^3 街区的纬度',
 '街区人口^3 街区的经度',
 '街区人口^2 平均入住率^2',
 '街区人口^2 平均入住率 街区的纬度',
 '街区人口^2 平均入住率 街区的经度',
 '街区人口^2 街区的纬度^2',
 '街区人口^2 街区的纬度 街区的经度',
 '街区人口^2 街区的经度^2',
 '街区人口 平均入住率^3',
 '街区人口 平均入住率^2 街区的纬度',
 '街区人口 平均入住率^2 街区的经度',
 '街区人口 平均入住率 街区的纬度^2',
 '街区人口 平均入住率 街区的纬度 街区的经度',
 '街区人口 平均入住率 街区的经度^2',
 '街区人口 街区的纬度^3',
 '街区人口 街区的纬度^2 街区的经度',
 '街区人口 街区的纬度 街区的经度^2',
 '街区人口 街区的经度^3',
 '平均入住率^4',
 '平均入住率^3 街区的纬度',
 '平均入住率^3 街区的经度',
 '平均入住率^2 街区的纬度^2',
 '平均入住率^2 街区的纬度 街区的经度',
 '平均入住率^2 街区的经度^2',
 '平均入住率 街区的纬度^3',
 '平均入住率 街区的纬度^2 街区的经度',
 '平均入住率 街区的纬度 街区的经度^2',
 '平均入住率 街区的经度^3',
 '街区的纬度^4',
 '街区的纬度^3 街区的经度',
 '街区的纬度^2 街区的经度^2',
 '街区的纬度 街区的经度^3',
 '街区的经度^4']
"""

X_ = poly.transform(X)
#在这之后,我们依然可以直接建立模型,然后使用线性回归的coef_属性来查看什么特征对标签的影响最大
reg = LinearRegression().fit(X_,y)
coef = reg.coef_

coef
"""
array([ 3.10740315e-04,  2.16381262e-05,  1.13681254e-06, -3.95160563e-07,
       -1.49166019e-07, -5.19379976e-05, -3.83264413e-07,  7.62142123e-07,
        8.97360753e-08, -9.55487085e-06, -1.23302472e-05, -1.96416393e-05,
       -2.42502952e-06, -4.43663893e-05,  2.25201042e-06, -2.04901953e-06,
        1.53656019e-05, -6.99739366e-06,  9.92670721e-06, -6.75302310e-06,
       -7.67933887e-04,  3.55694977e-05,  1.32771450e-05,  2.58250296e-05,
       -1.18163632e-05,  3.52124404e-06, -1.08195681e-04, -5.25094383e-06])
"""

[*zip(poly.get_feature_names(X.columns),reg.coef_)]

"""
[('1', 0.00031074031527074516),
 ('住户收入中位数', 2.1638126249588402e-05),
 ('房屋使用年代中位数', 1.1368125378777994e-06),
 ('平均房间数目', -3.951605626628894e-07),
 ('平均卧室数目', -1.4916601876216981e-07),
 ('街区人口', -5.1937997607023026e-05),
 ('平均入住率', -3.8326441329667543e-07),
 ('街区的纬度', 7.621421227125262e-07),
 ('街区的经度', 8.973607531665007e-08),
 ('住户收入中位数^2', -9.554870847805443e-06),
 ('住户收入中位数 房屋使用年代中位数', -1.2330247175311625e-05),
 ('住户收入中位数 平均房间数目', -1.9641639326505202e-05),
 ('住户收入中位数 平均卧室数目', -2.425029519593425e-06),
 ('住户收入中位数 街区人口', -4.4366389267125575e-05),
 ('住户收入中位数 平均入住率', 2.25201041611873e-06),
 ('住户收入中位数 街区的纬度', -2.0490195309310308e-06),
 ('住户收入中位数 街区的经度', 1.5365601874845908e-05),
 ('房屋使用年代中位数^2', -6.9973936594299735e-06),
 ('房屋使用年代中位数 平均房间数目', 9.926707208253872e-06),
 ('房屋使用年代中位数 平均卧室数目', -6.753023095400608e-06),
 ('房屋使用年代中位数 街区人口', -0.000767933887401416),
 ('房屋使用年代中位数 平均入住率', 3.5569497651543913e-05),
 ('房屋使用年代中位数 街区的纬度', 1.3277144997013453e-05),
 ('房屋使用年代中位数 街区的经度', 2.5825029646670777e-05),
 ('平均房间数目^2', -1.1816363182675111e-05),
 ('平均房间数目 平均卧室数目', 3.5212440375231096e-06),
 ('平均房间数目 街区人口', -0.00010819568131366495),
 ('平均房间数目 平均入住率', -5.250943828704185e-06),
 ('平均房间数目 街区的纬度', 4.71253425751724e-07),
 ('平均房间数目 街区的经度', 1.6961141181024806e-07)]
"""

#放到dataframe中进行排序
coeff = pd.DataFrame([poly.get_feature_names(X.columns),reg.coef_.tolist()]).T
coeff.head()

image.png

coeff.columns = ["feature","coef"]
coeff.sort_values(by="coef")

image.png

可以发现,不仅数据的可解释性还存在,我们还可以通过这样的手段做特征工程——特征创造。多项式帮助我们进行了一系列特征之间相乘的组合,若能够找出组合起来后对标签贡献巨大的特征,那我们就是创造了新的有效特征,对于任何学科而言发现新特征都是非常有价值的。

在加利佛尼亚房屋价值数据集上来再次确认多项式回归提升模型表现的能力:

#顺便可以查看一下多项式变化之后,模型的拟合效果如何了
poly = PolynomialFeatures(degree=4).fit(X,y)
X_ = poly.transform(X)

reg = LinearRegression().fit(X,y)
reg.score(X,y)
# 0.606232685199805

from time import time
time0 = time()
reg_ = LinearRegression().fit(X_,y)
print("R2:{}".format(reg_.score(X_,y)))
print("time:{}".format(time()-time0))
"""
R2:0.745020341164214
time:0.6845390796661377
"""

#假设使用其他模型?
from sklearn.ensemble import RandomForestRegressor as RFR

time0 = time()
print("R2:{}".format(RFR(n_estimators=100).fit(X,y).score(X,y)))
print("time:{}".format(time()-time0))
"""
R2:0.974349686863104
time:9.077104330062866
"""

线性还是非线性模型

另一个围绕多项式回归的核心问题是,多项式回归是一个线性模型还是非线性模型呢?从我们之前对线性模型的定义来看,自变量上需要没有高次项才是线性模型,按照这个定义,在x上填上高次方的多项式回归肯定不是线性模型了。然而事情却没有这么简单。来看原始特征为二维,多项式次数为二次的多项式回归表达式:

image.png

经过变化后的数据有六个特征,分别是:

image.png

我们能够一眼看出从第四个特征开始,都是高次特征,而这些高次特征与y之间的关系必然不是线性的。但是我们也可以换一种方式来思考这个问题:假设我们不知道这些特征是由多项式变化改变来的,我们只是拿到了含有六个特征的任意数据,于是现在对于我们来说这六个特征就是:

image.png

我们通过检验发现, z1z_1z4z_4z3z_3 之间存在一定的共线性, z2z_2也是如此,但是现实中的数据不太可能完全不相关,因此一部分的共线性是合理的,我们没有任何理由去联想到说,这个数据其实是由多项式变化来生成的。所以我们了线性回归来对数据进行拟合,然后得到了方程:

image.png

这妥妥的是一个线性方程没错:并不存在任何高次项,只要拟合结果不错,大概也没有人会在意这个六个特征的原始数据究竟是怎么来的,那多项式回归不就变成一个含有部分共线性的线性方程了么?在许多教材中,多项式回归被称为“线性回归的一种特殊情况”,这就是为什么许多人会产生混淆,多项式回归究竟是线性模型还是非线性模型呢?这就需要聊到我们对”线性模型“的狭义和广义定义了。

狭义线性模型 vs 广义线性模型

  • 狭义线性模型:自变量上不能有高此项,自变量与标签之间不能存在非线性关系。
  • 广义线性模型:只要标签与模型拟合出的参数之间的关系是线性的,模型就是线性的。这是说,只要生成的一系列之间没有相乘或者相除的关系,我们就认为模型是线性的

就多项式回归本身的性质来说,如果我们考虑狭义线性模型的定义,那它肯定是一种非线性模型没有错——否则如何能够处理非线性数据呢,并且在统计学中我们认为,特征之间若存在精确相关关系或高度相关关系,线性模型的估计就会被“扭曲“,从而失真或难以估计准确。多项式正是利用线性回归的这种”扭曲“,为线性模型赋予了处理非线性数据的能力。但如果我们考虑广义线性模型的定义,多项式回归就是一种线性模型,毕竟它的系数之间也没有相乘或者相除。

另外,当Python在处理数据时,它并不知道这些特征是由多项式变化来的,它只注意到这些特征之间高度相关,然而既然你让我使用线性回归,那我就忠实执行命令,因此Python看待数据的方式是我们提到的第二种:并不了解数据之间的真实关系的建模。于是Python会为我们建立形如式子(2)的模型。这也证明了多项式回归是广义线性模型。所以,我们认为多项式回归是一种特殊的线性模型,不过要记得,它中间的特征包含了相当的共线性,如果处理线性数据,是会严重失误的。

总结一下,多项式回归通常被认为是非线性模型,但广义上它是一种特殊的线性模型,它能够帮助我们处理非线性数据,是线性回归的一种进化。大家要能够理解多项式回归的争议从哪里来,并且能够解释清楚观察多项式回归的不同角度,以避免混淆。

另外一个需要注意的点是,线性回归进行多项式变化后被称为多项式回归,但这并不代表多项式变化只能够与线性回归连用。在现实中,多项式变化疯狂增加数据维度的同时,也增加了过拟合的可能性,因此多项式变化多与能够处理过拟合的线性模型如岭回归,Lasso等来连用,与在线性回归上使用的效果是一致的,感兴趣的话大家可以自己尝试一下。

到这里,多项式回归就全部讲解完毕了。多项式回归主要是通过对自变量上的次方进行调整,来为线性回归赋予更多的学习能力,它的核心表现在提升模型在现有数据集上的表