15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

过拟合与欠拟合

一. 概念

之前,我们介绍过拟合的概念。拟合指的是构建的模型能够符合样本数据的特征。与拟合相关的两个概念是欠拟合与过拟合。

  • 欠拟合:模型过于简单,未能充分捕获样本数据的特征。表现为模型在训练集上的效果不好。
  • 过拟合:模型过于复杂,过分捕获样本数据的特征,从而将样本数据中一些特殊特征当成了共性特征。表现为模型在训练集上的效果非常好,但是在未知数据上的表现效果不好。

进一步解释

欠拟合
考虑太少了,数据集里很多能影响到的因素没有考虑到。
Eg. 房屋面积和房价,Y_hat = wx + b可以说是欠拟合,有很多因素能影响房价,除了面积。

过拟合
每一个细节都没放过,每一个特征都没放过,不是训练起来很完美吗?
建筑年代,材料,楼层,考虑到很多因素,很可能需要100元线性回归。
所以说在训练集的表现很不错,但是太过于考虑训练集特征。
很可能在测试集上表现的不好,过拟合就是太过于复杂,对特征过分依赖。
表现就是:训练集表现好,测试集不是那么好。
eg. 判断人的性别是男还是女?
过拟合,只要是有胡子,就是男人。

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
左图,欠拟合。
真实值和样本数据why没有完全重合?
现实数据,因为有噪声。

真实值是曲线,用直线来进行预测,就是一种欠拟合。
R2R^{2}只有0.474 效果并不是很好。
就像预测房屋价格,只考虑面积因素,就是欠拟合。

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
该图训练集和测试集都表示的不错。

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
穿过去,趋势大, 在训练集上表现好,都传过去了。
在未知数据上表现不好, 测试集上,R2R^{2} 都是负的了,和真实值差别大。

eg. 图像的话,抓的太详细了,穿过每个点;判断男女性别的话好像有个汗毛就是男的了。
训练集只是样本的一部分。

2. 解决方案

如果产生欠拟合,可以采用如下方式,来达到更好的拟合效果。

  • 增加迭代次数
  • 增加模型复杂度(例如,引入新的特征)
  • 通过多项式扩展
  • 使用更复杂的模型(例如非线性模型)

如果产生过拟合,可以采用如下方式,来降低过拟合的程度。

  • 收集更多的数据
  • 正则化
  • 降低模型的复杂度
  • 减少迭代次数
  • 选择简单的模型

现在,我们来介绍下多项式扩展与正则化。

并不是每一种方法都是有效,要去做实验,分别解释。

如果欠拟合

eg. 走楼梯,100个台阶,50步,没达到极值点,误差还是比较大,欠拟合。
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

1. 增加迭代次数,就能达到

多次进行循环就能达到,而欠拟合,就是过于简单。

2. 增加模型复杂度

eg. 就像房价,用 y = wx + b

3. 多项式扩展

扩展到多维度;维度增加,拟合能力变强。
一个线变成曲线,变成平面。
eg. 以前是直的,现在可以打弯。

4. 更换模型

换个模型,找个其他的模型尝试。
eg. 线性模型处理不好的话,找个非线性的模型。
相比较增加复杂度,不换模型。

如果过拟合
1. 数据收集

数据集分成4个部分,左上角的数据特别多,其他少。将其他部分的数据多收集些,再放到数据集中。这样就能捕获更多特征。
但是,现实中收集数据可能很麻烦。
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

1. 数据收集
2. 正则化
3. 降低模型的复杂度

看这个线的复杂度,咱们将多项式的阶数下降。
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

4. 减少迭代次数

迭代多了 过拟合
迭代少了 欠拟合

5. 选择简单的模型

多项式扩展 解决欠拟合

我们可以使用线性回归模型来拟合数据,然而,在现实中,数据未必总是线性(或接近线性)的。当数据并非线性时,直接使用LinearRegression的效果可能会较差,产生欠拟合。

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

mpl.rcParams["font.family"] = "SimHei"
mpl.rcParams["axes.unicode_minus"] = False

x = np.linspace(0, 10, 50)
# 真实的数据分布。该分布是非线性的。
y = x * np.sin(x)
# np.newaxis 表示进行维度的扩展,可以认为是增加一个维度,该维度为1。
# 此种方式也可以通过reshape方法来实现。
X = x[:, np.newaxis]
lr = LinearRegression()
lr.fit(X, y)
# 输出在训练集上的分值。查看线性回归LinearRegression在非线性数据集上的拟合效果。
print(lr.score(X, y))
# 将样本数据以散点图进行绘制。
plt.scatter(x, y, c="g", label="样本数据")
# 绘制预测值(模型的回归线)
plt.plot(X, lr.predict(X), "r-", label="拟合线")
plt.legend()
plt.show()
# 结果:R ^ 2值为0.05908132146396671,模型在训练集上表现非常不好,产生欠拟合。

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

是真实线,还没有加噪声。就是想看,非线性再线性上表现怎么样。
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
表示要进行维度的扩展
可以认为是增加一个维度,该维度为1
Why要增加一个维度?
意味着x能否送到fit?不能
一维不能
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
X要变成二维
现在是 50,
变成50,1
之前是reshape
现在变成
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

# x = np.linspace(0, 10, 50)
# print(x.shape)
# print(x[:, np.newaxis].shape)

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

习惯大写
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
欠拟合 是不涉及未知数据的,欠拟合是训练集相关
跟未知数据无关

Eg. 模拟题都做不好

看下效果
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
将样本数据以散点图进行绘制

真实值
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
还差一个预测值,就是一条回归线,模型的回归线。
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
Show()在jupyter里面可以不加,pycharm里面得加,这也是 sinx x
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
综上看,这个拟合效果不好。所以线性回归 对非线性 拟合效果不好。相当于蒙。

因为线性回归是直的,在训练集上表现不好,产生欠拟合现象,R2R^{2} 值很低。

欠拟合怎么办,多项式可扩展

此时,我们可以尝试使用多项式扩展来进行改进。
多项式扩展,可以认为是对现有数据进行的一种转换,通过将数据映射到更高维度的空间中,该模型就可以拟合更广泛的数据。
假设,我们有如下的二元线性模型:
y^=w0+w1x1+w2x2\hat{y} = w_{0} + w_{1}x_{1} + w_{2}x_{2}
如果该模型的拟合效果不佳,我们就可以对该模型进行多项式扩展。例如,我们进行二项式扩展(也可以进行更高阶的扩展),结果为:
y^=w0+w1x1+w2x2+w3x1x2+w4x12+w5x22\hat{y} = w_0 + w_1 x_1 + w_2 x_2 + w_3 x_1 x_2 + w_4 x_1^2 + w_5 x_2^2
当进行多项式扩展后,我们就可以认为,模型由以前的直线变成了曲线。从而可以更灵活的去拟合数据。

多项式拟合

经过多项式扩展后,我们依然可以使用之前的线性回归模型去拟合数据。这是因为,我们可以假设:
z=[x1,x2,x1x2,x12,x22]z = [x_1, x_2, x_1 x_2, x_1^2, x_2^2]
这样,之前的模型就会变成:
y^=w0+w1z1+w2z2+w3z3+w4z4+w5z5\hat{y} = w_0 + w_1 z_1 + w_2 z_2 + w_3 z_3 + w_4 z_4 + w_5 z_5
从而,我们依然可以认为,这还是一种线性模型。

线性回归本身解决不了,可以多项式扩展
多元线性回归 是直的 是一个面
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

怎么进行多项式扩展?
扩展到几阶?
之前说过线性?

  1. 直的
  2. 最高次项是1
    多项式扩展 让它扩展

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
二维变为五维
空间中 张开了

一维 线
二维 平面
三维 超平面

多项式扩展,把它由一维的线变为面,变为超平面

2个维度 平面 变成 5个维度 超平面

扩展是怎么来的?扩展到几阶
所有的特征任意组合

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

W几不重要
B就是w

多项式转换规则

我们可以使用sklearn中提供的PolynomialFeatures类来实现多项式扩展。通过powers_属性可以获取扩展之后每个输入特征的指数矩阵。指数矩阵的形状为[输出特征数, 输入特征数]。powers_[i, j]表示第i个输出特征中,第j个输入特征的指数值。
例如,如果输入样本的特征数为2,多项式扩展阶数为2,则指数矩阵为:
powers=[001001201102]powers_ = \begin{bmatrix} 0 & 0\\ 1 & 0\\ 0 & 1\\ 2 & 0\\ 1 & 1\\ 0 & 2 \end{bmatrix}
多项式转换,其实就是将输入特征转换成输出特征。矩阵的每行对应每个输出特征,每列对应每个输入特征的指数,例如,对于两个输入特征x1x2x_1与x_2来讲,多项式转换之后的值为:
[x10x20, x11x20, x10x21, x12x20, x11x21, x10x22][x_1^0x_2^0,\ x_1^1x_2^0,\ x_1^0x_2^1,\ x_1^2x_2^0,\ x_1^1x_2^1,\ x_1^0x_2^2]
即:
[1, x1, x2, x12, x1x2, x22][1,\ x_1,\ x_2,\ x_1^2,\ x_1 x_2,\ x_2^2]

多项式扩展的规则:
每个输入特征分别带有一个指数(指数值为非负整数),然后让指数之间进行任意可能的组合,但要保证所有的指数之和不能大于扩展的阶数。


# 类似PolynomialFeatures这样功能的类(数据预处理),所有的转换方法都叫做transform。
# 拟合与转换可以同时进行,方法名称都叫做fit_transform。

import numpy as np
# sklearn.preprocessing 该模块提供数据预处理的相关功能。
# PolynomialFeatures多项式扩展类,可以对模型进行n阶扩展。从而可以解决欠拟合问题。
from sklearn.preprocessing import PolynomialFeatures

X = np.array([[1, 2], [3, 4]])
# X = np.array([[1, 2, 3], [3, 4, 5]])
# 定义多项式扩展类,参数指定要扩展的阶数。
poly = PolynomialFeatures(2)
# 拟合模型,计算power_的值。
# poly.fit(X)
# 对数据集X进行多项式扩展,即进行多项式转换。
# r = poly.transform(X)
# 我们可以令fit与transofrm两步一起完成。
r = poly.fit_transform(X)

print("转换之后的结果:")
print(r)
print("指数矩阵:")
# 指数矩阵,形状为(输出特征数,输入特征数)。
print(poly.powers_)
print(f"输入的特征数量:{poly.n_input_features_}")
print(f"输出的特征数量:{poly.n_output_features_}")

# 根据power_矩阵,自行计算转换结果。
# 循环获取X中的每一个样本。
for x1, x2 in X:
    for e1, e2 in poly.powers_:
        print(x1 ** e1 * x2 ** e2, end="\t")
    print()

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
以前的非线性回归 还能适用吗?
Z1 = x1 … Z5
带入上面的

又成线性模型了,之前的线性回归模型 对多项式扩展之后的方程同样能够适用

尽管最高次项,只要经过转换,仍然能够进行适用

可以假设,所以可以用liner regre处理多项式
以前2个特征
现在5个特征的超平面拟合能力强

多项式特征 这样一个类 可以实现一个多项式扩展
在以前的特征上转换
从低位 的空间映射到高维的空间

拟合之后,有powers属性,下划线
得到一个矩阵,输出的特征的数量

以及每一个输入特征的
扩展的时候没有必要自己去数,如何扩展咱么得知道细节是如何扩展

Powers 扩展后 每一个特征的 指数

Power_可以看成二维数组
形状

每一个输入特征都会带指数
每一列 特征的指数值
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
输入特征: 转换之前的特征数,因为我们现在要实现多项式转换
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
其实转换规则就是:多项式扩展
以前 2个特征 现在扩展到5个特征 不考虑截距
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
化简 第一个是1

二维 输入特征 变成 五维输出特征
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

程序解释

新的 模块 sklern.preprocessing 数据预处理的模块
多项式扩展 相当于 数据转换 相当于 数据预处理
Metics 提供 评估 的
多项式扩展类

2行2列 1,2是一个样本
1 x1 2 x2
一列是一个特征
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
定义了一个多项式对象
不要用predict, 这个模型不是负责预测的 Poly
把转换的结果交给别的模型进行预测

只有x没有y
拟合 是干什么 试求powers
扩展的阶数不同 powers数量不一样
Fit就是根据传递额阶数 计算powers的值
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
有两个样本
转换成两个
根据
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
指数矩阵就是 形状为
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
换成3阶
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
优化:
合二为一
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

poly.fit(X)
r = poly.fit_transform(X)

再来,根据power矩阵,自行计算转换结果

拆包
X1 x2

对powers矩阵循环
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题
e1次幂,还是指数后,乘积,只不过使用循环
结合性,乘方有优先性
通用上的预处理规则,Fit就是计算转换的规则
没有powers数组,是转换不了的;而这个数组,是通过数组拟合出来的

多项式如何进行转换?
扩展就是多项式转换?

多项式扩展解决欠拟合,对之前的问题,进行处理欠拟合的问题

现在,就让我们对之前的程序来进行多项式扩展,尝试解决欠拟合问题。

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures

mpl.rcParams["font.family"] = "SimHei"
mpl.rcParams["axes.unicode_minus"] = False

x = np.linspace(0, 10, 50)
y = x * np.sin(x)
X = x[:, np.newaxis]
figure, ax = plt.subplots(2, 3)
figure.set_size_inches(18, 10)
ax = ax.ravel()

# n为要进行多项式扩展的阶数。
for n in range(1, 7):
    # 注意:多项式1阶扩展,相当于没有扩展(没有变化)。
    poly = PolynomialFeatures(degree=n)
    X_transform = poly.fit_transform(X)
    # 注意:多项式扩展之后,我们依然可以将数据视为线性的,因此,我们还是可以通过之前的
    # LinearRegression来求解问题。
    lr = LinearRegression()
    # 使用多项式扩展之后的数据集来训练模型。
    lr.fit(X_transform, y)
    ax[n - 1].set_title(f"{n}阶,拟合度:{lr.score(X_transform, y):.3f}")
    ax[n - 1].scatter(x, y, c="g", label="样本数据")
    ax[n - 1].plot(x, lr.predict(X_transform), "r-", label="拟合线")
    ax[n - 1].legend()

生成数据集 50个点
创建y 非线性
把x变成二维的,使用np.newaxis
50,
50,1

接下来进行可视化的绘图操作
看一下多项式扩展的效果好不好
R^2值怎么样
数据如何进行的分布,线靠的近不近

阶数很关键,画6个子图 每个阶数的拟合情况
每一个阶的r^2
Subplots子绘图区域
画布大小 figure.set 因为2 3 宽
Ravel() 变成一层循环,之前是二维
N表示要扩展的阶数
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

N=1 1阶 数组是0开始 所以n-1
标题
拟合度 score求解
把x_transform放进去
把样本数据画一下,看拟合情况
散点画完了,画预测线, x传进来,需要有一个对应的y值

特征多了,也就是复杂度越来越多
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

通过多项式扩展 解决了欠拟合的问题

Why能这么做?
输入的时候特征比较少,所以咱么就给它映射到更高维的空间(超平面)
咱们拟合的能力就会变强

维度越高,越能捕获更多的数据
二维图来看,线的弯曲程度越高

流水线

在上例中,我们使用多项式对训练数据进行了转换(扩展),然后使用线性回归类(LinearRegression)在转换后的数据上进行拟合。可以说,这是两个步骤。我们虽然可以分别去执行这两个步骤,然而,当数据预处理的工作较多时,可能会涉及更多的步骤(例如标准化,编码等),此时再去一一执行会显得过于繁琐。

流水线(Pipeline类)可以将每个评估器视为一个步骤,然后将多个步骤作为一个整体而依次执行,这样,我们就无需分别执行每个步骤。流水线中的所有评估器(除了最后一个评估器外)都必须具有转换功能(具有transform方法)。

流水线具有最后一个评估器的所有方法。当调用某个方法f时,会首先对前n - 1个(假设流水线具有n个评估器)评估器执行transform方法(如果调用的f是fit方法,则n-1个评估器会执行fit_transform方法),对数据进行转换,然后在最后一个评估器上调用f方法。

例如,当在流水线上调用fit方法时,将会依次在每个评估器上调用fit方法,然后再调用transform方法,接下来将转换之后的结果传递给下一个评估器,直到最后一个评估器调用fit方法为止(最后一个评估器不会调用transform方法)。而当在流水线上调用predict方法时,则会依次在每个评估器上调用transform方法,最后在最后一个评估器上调用predict方法。

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
# sklearn库提供的流水线类,作用就是将多个评估器打包成一个整体,这样,当我们对流水线进行某些操作时,
# 流水线内的所有评估器都会执行相关的操作。这样,就可以作为一个整体而执行,无需我们分别对每个评估器
# 单独进行执行。
from sklearn.pipeline import Pipeline

mpl.rcParams["font.family"] = "SimHei"
mpl.rcParams["axes.unicode_minus"] = False

x = np.linspace(0, 10, 50)
y = x * np.sin(x)
X = x[:, np.newaxis]
# 定义流水线中的每一个评估器。
# 格式为一个含有元组的列表。每个元组定义流水线中的一个步骤。
# 元组中含有两个元素。前面的元素为流水线步骤的名称,后面的
# 元素为该流水线步骤处理的对象。
estimators = [("poly", PolynomialFeatures()), ("lr", LinearRegression())]
# 创建流水线对象,将评估器数组传递给流水线类。
pipeline = Pipeline(estimators)
# 流水线的steps属性,可以返回流水线所有的步骤。包括步骤名与该步骤的处理对象。
# pipeline.steps
# 流水线的named_steps属性,与steps属性相似,只是类型不同(字典类型)。
# pipeline.named_steps
# 设置流水线对象的参数信息。
# 如果需要为流水线的某个步骤处理对象设置相关的参数,则参数名为:步骤名__处理对象参数。
pipeline.set_params(poly__degree=8)
# 获取流水线支持设置的所有参数。
# print(pipeline.get_params())

# 在流水线对象上调用fit方法,相当于对除了最后一个评估器之外的所有评估器调用fit_transform方法,
# 然后最后一个评估器调用fit方法。
pipeline.fit(X, y)
# 流水线对象具有最后一个评估器的所有方法。
# 当通过流水线对象,调用最后一个评估器的方法时,会首先调用之前所有评估器的transform方法。
score = pipeline.score(X, y)
plt.title(f"8阶,拟合度:{score:.3f}")
plt.scatter(X, y, c="g", label="样本数据")
# 当调用流水线对象的predict方法时,除最后一个评估器外,其余评估器会调用transform方法,然后,最后
# 一个评估器调用predict方法。
plt.plot(X, pipeline.predict(X), "r-", label="拟合线")

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

第一步:
使用多项式进行扩展。

第二步:
使用线性回归类,对多项式扩展之后的结果,进行训练,
预测结果。

但是再实际的机器学习过程中,可能更复杂
数据预处理,很多步骤
流水线 封罐头 很多步 都能作为一个整体进行操作

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

这个操作太繁琐
直接打包进 流水线,然后流水线调用fit就行了,流水线除了最后一个调用fit其他都会调用fit transform

最后是predict,不是fit
哪怕不是进行流水线,我们永远都是在训练集上进行fit,
我们现在调用predict的,实在测试集上,不要再训练集上fit

测试

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

看一下流水线的程序
之前是分成2步的,现在我们分成一步实现
新库
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

执行什么操作呢?
定义流水线 里面的 每一个评估器
是一个含有元组的列表
后面是评估期的对象
名字 步骤要处理的对象
创建流水线对象 把相关评估器数组 传递给流水线内

步骤
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

名字 对象 顺便把默认的参数也显示出来
单独的想看流水线的处理对象,用这种 字典的方法
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

每个步骤有了,获得相关步骤就很简单
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

两部一起完成了
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

之前是 转换之后的
15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

15. 线性回归模型的过拟合&欠拟合 ——程序解决模型欠拟合的问题

流水线的类 pipeline 很有用,放到一起,统一执行。
优势:
1.放到一起
2. 可以设置参数