目录
1 什么是多项式回归?
1.1 一个例子:
下面的数据,虽然我们可以使用线性回归来拟合这些数据,但是这些数据更像是一条二次曲线,相应的方程是:如果将理解为一个特征,将x理解为另外一个特征,本来我们的样本只有一个特征x,现在我们把他看成有两个特征的一个数据集。
我们为样本多添加了一些特征,这些特征是原来样本的多项式项,增加了这些特征之后,我们可以使用线性回归的思路更好的拟合数据,这就是所谓的多项式回归。
1.2 多项式回归和线性回归的联系
多项式线性回归在机器学习算法上并没有新的地方,完全是使用线性回归的思路。他的关键在于为原来的样本,添加新的特征。而我们得到新的特征的方式是原有特征的多项式的组合。 采用这样的方式,我们就可以解决一些非线性的问题。
1.3 多项式回归为啥也被称为多项式升维呢?
PCA是对数据进行降维处理,而多项式回归是对数据升维。多项式回归之所以也称为多项式升维,是因为它通过将输入特征的多项式扩展,将原始低维特征空间升高为更高维度的特征空间。
在简单线性回归中,我们使用一个线性模型来拟合数据,假设输入特征只有一个。但是在某些情况下,数据的关系可能并不是线性的,这时候使用简单的线性模型就不能很好地拟合数据。多项式回归通过引入多项式特征,将输入特征的幂次进行组合,以增加模型的灵活性,能够更好地拟合非线性关系的数据。
具体而言,多项式回归会将输入特征的幂次进行组合,形成新的特征,然后使用线性回归模型拟合这些新的特征。例如,对于一个二次多项式回归,输入特征 x 会被扩展为 x、x^2 两个特征,形成一个二维特征空间。这样,原先的一维特征空间被升高为二维特征空间,因此称之为多项式升维。
2 过拟合与欠拟合
在多项式回归中,欠拟合(underfitting)和过拟合(overfitting)是两种常见的模型拟合问题。
2.1 欠拟合:
算法所训练的模型不能完整表述数据关系。
欠拟合指的是模型无法很好地拟合训练数据,即模型不能捕捉到数据中的真实模式和趋势。当模型出现欠拟合时,通常是因为模型过于简单或者特征表达能力不足。在多项式回归中,如果选择的多项式次数过低,模型可能无法很好地拟合数据的非线性关系,导致欠拟合现象。如下图所示:
2.2 过拟合:
算法所训练的模型过多的表达了数据间的噪音关系。
过拟合指的是模型过于复杂,过度拟合了训练数据,但在新的未见过的数据上表现较差。过拟合的模型在训练数据上表现很好,但在新数据上的泛化能力较差。在多项式回归中,如果选择的多项式次数过高,模型可能会过度拟合训练数据,将数据中的噪声和异常点也纳入拟合,导致过拟合现象。例如,我们使用了一个非常高的维度拟合样本数据,虽然误差更小,但是得到的曲线完全不是我们想要的样子。曲线为了拟合所有的样本点,变的太过复杂了,这种情况就是过拟合
过拟合会导致模型的泛化能力很弱,那么什么是泛化能力呢?
2.3 泛化能力:
测试数据对于我们的模型是全新的数据,如果使用训练数据获得的模型面对测试数据也能
获得很好的结果,那么我们就说我们的模型泛化能力是很强的。 如果我们的模型面对测
试数据结果很差的话,那么他的泛化能力就很弱。
2.4 模型准确率和复杂程度的关系:
对于多项式模型来说,回归的阶数越高,模型会越复杂。在下图中,横轴是模型复杂度(对于不同的算法来说,代表的是不同的意思,比如对于多项式回归来说,是阶数越高,越复杂;对于KNN来
说,是K越小,模型越复杂,k越大,模型最简单,当k=n的时候,模型就简化成了看整个样本里,哪种样本最多,当k=1来说,对于每一个点,都要找到离它最近的那个点),另一个维度是模型准确率。
通常对于这样一个图,会有两根曲线:
(1)一个是对于训练数据集来说的,模型越复杂,模型准确率越高,因为模型越复杂,对训练数据集的拟合就越好,相应的模型准确率就越高。
(2)对于测试数据集来说,在模型很简单的时候,模型的准确率也比较低,随着模型逐渐变复杂,对测试数据集的准确率在逐渐的提升,提升到一定程度后,如果模型继续变复杂,那么我们的模型准确率将会进行下降(欠拟合->正合适->过拟合)
3 学习曲线:
3.1 定义:
随着训练样本的逐渐增多,算法训练出的模型的表现能力。
3.2 线性回归的学习曲线:
下图观察线性回归的学习曲线:观察线性回归模型,随着训练数据集增加,性能的变化( 横轴代表用于训练的数据,纵轴表示误差)
从趋势上看:在训练数据集上,误差是逐渐升高的。这是因为我们的训练数据越来越多,我们的数据点越难得到全部的累积,不过整体而言,在刚开始的时候误差变化的比较快,后来就几乎不变了。在测试数据集上,在使用非常少的样本进行训练的时候,刚开始我们的测试误差非常的大,当训练样本大到一定程度以后,我们的测试误差就会逐渐减小,减小到一定程度后,也不会小太多,达到一种相对稳定的情况。在最终,测试误差和训练误差趋于相等,不过测试误差还是高于训练误差一些,这是因为,训练数据在数据非常多的情况下,可以将数据拟合的比较好,误差小一些,但是泛化到测试数据集的时候,还是有可能多一些误差。
3.3 线性回归、2阶多项式、20阶多项式学习曲线比较:
- 2阶多项式和线性回归的学习曲线是类似的,不同在于线性回归的学习曲线误差在1.5至1.8左右;2阶多项式回归学习曲线误差稳定在了1.0,0.9左右;2阶多项式稳定的误差比较低,说明使用二阶线性回归的性能是比较好的。
- 20阶多项式在数据量偏多的时候,训练数据集拟合的是比较好的,但是测试数据集的误差增大了很多。这就是过拟合的结果,他的泛化能力是不够的。
4 只使用训练集和测试集两种数据集的危害及解决方法
4.1 危害:
使用分割训练数据集和测试数据集来判断我们的机器学习模型性能的好坏,虽然是一个非常好的方案,但是会产生一个问题:针对特定测试数据集过拟合。
我们每次使用测试数据来分析性能的好坏。一旦发现结果不好,我们就换一个参数(可能是阶数也可能是其他超参数)重新进行训练。这种情况下,我们的模型在一定程度上围绕着测试数据集打转。也就是说我们在寻找一组参数,使得这组参数训练出来的模型在测试结果集上表现的最好。但是由于这组测试数据集是已知的,我们相当于在针对这组测试数据集进行调参,那么他也有可能产生过拟合的情况,也就是我们得到的模型针对测试数据集过拟合了。
4.2 解决办法:
那么怎么解决这个问题呢? 解决的方式其实就是:我们需要将我们的问题分为三部分,这三部分分别是训练数据集,验证数据集,测试数据集。 我们使用训练数据集训练好模型之后,将验证数据集送给这个模型,看看这个训练数据集训练的效果是怎么样的,如果效果不好的话,我们重新换参数,重新训练模型。直到我们的模型针对验证数据来说已经达到最优了。 这样我们的模型达到最优以后,再将测试数据集送给模型,这样才能作为衡量模型最终的性能。换句话说,我们的测试数据集是不参与模型的创建的,而其他两个数据集都参与了训练。但是我们的测试数据集对于模型是完全不可知的,相当于我们在使用这个模型完全不知道的数据。
4.3 遗留的问题:
这种方法还会有一个问题。由于我们的模型可能会针对验证数据集过拟合,而我们只有一份验证数据集,一旦我们的数据集里有比较极端的情况,那么模型的性能就会下降很多,那么为了解决这个问题,就有了交叉验证。
5 交叉验证
在训练模型的时候,通常把数据分成k份,例如分成3份(ABC)(分成k份,k属于超参数),这三份进行一定规则的组合后分别作为验证数据集和训练数据集。这样组合后可以分别产生三个模型,这三个模型,每个模型在测试数据集上都会产生一个性能的指标,这三个指标的平均值作为当前这个算法训练出的模型衡量的标准。 由于我们有一个求平均的过程,所以不会因为一份验证数据集中有比较极端的数据而导致模型有过大的偏差,这比我们只分成训练、验证、测试数据集要更加准确。
6 模型正则化(Regularization):
6.1 定义:
模型正则化 是通过约束模型参数值的大小实现解决模型方差过大(过拟合)问题的一种标准处理手段。通过模型正则化处理可以在保持模型具有较高复杂度的前提下提高模型的泛化能力。
6.2 提出的背景:
多项式回归是为了解决输入空间和输出空间非线性关系拟合的问题,随着多项式的幂次越高,拟合度越好。但同时带来了另一个问题,就是模型的过拟合,在训练数据中表现良好的模型,在测试数据中并不理想。研究表明,模型中多项式系数越多越大,导致模型越复杂越容易过拟合,为了缓解多项式回归中的过拟合问题,兼顾误差和模型系数累计值均达到最小,在原有的损失函数中加入多项式系数的影响,即模型正则化,从而衍生出以下三种回归模型——①岭回归 Ridge Regression ②LASSO回归 LASSO Regression ③弹性网络回归 Elastic Net 。
6.3 原理:
对上述公式的一些解释:
- 对于θ的求和i是从1到n,没有将加进去,因为他不是任意一项的系数,他只是一个截距,决定了整个曲线的高低,但是不决定曲线每一部分的陡峭和缓和。
- θ求和的系数二分之一是一个惯例,加不加都可以,加上的原因是因为,将来对θ2求导的时候可以抵消系数2,方便计算。不要也是可以的。
- α实际上是一个超参数,代表在我们模型正则化下新的损失函数中,我们要让每一个θ尽可能的小,小的程度占我们整个损失函数的多少,如果α等于0,相当于没有正则化;如果α是正无穷的话,那么我们主要的优化任务就是让每一个θ尽可能的小。
6.4 岭回归 Ridge Regression:
以系数平方和的形式存在于目标函数中,为了调和误差与系数对损失函数的影响程度,引入了一个超参数。
下图是对20项多项式选择不同α 的岭回归:
- α=0.0001: 通过使用岭回归,使得我们的均方误差小了非常多,曲线也缓和了非常多;
- α=1:均差误差更加的缩小,并且曲线越来越趋近于一根倾斜的直线;
- α=100:得到的误差依然是比较小,但是比之前(α =1)大了些,说明正则化做的有些过头了;
- α=10000000 :我们的模型实际上相当于就是在优化θ的平方和这一项,使得其最小(因为MSE的部分相对非常小)。而使得θ的平方和最小,就是使得每一个θ都趋近于0,这个时候曲线就趋近于一根直线了。
优缺点:
岭回归的优点:
- 可以有效地降低模型的方差,减少过拟合的风险。
- 对于具有共线性的数据,岭回归可以稳定模型的估计结果,提高模型的鲁棒性。
- 岭回归的正则化项采用L2范数,可以保留所有特征变量,并对所有特征进行缩放,使得模型对各个特征都有一定的贡献。
岭回归的缺点:
- 岭回归不能进行特征选择,即无法将某些不相关的特征的系数缩减为零。
- 当数据集的特征维度非常高时,岭回归可能会导致模型变得过于复杂,难以解释。
6.5 LASSO回归:
以系数绝对值累计和的形式存在于目标函数中,为了调和误差与系数对损失函数的影响程度,引入了一个超参数
下图是对20项多项式选择不同α 的LASSO回归:
优缺点:
LASSO回归的优点:
- LASSO回归的正则化项采用L1范数,具有稀疏性,可以将某些不相关的特征的系数缩减为零,实现特征选择。
- LASSO回归在具有共线性的数据中可以将相关特征选出,提供更简洁且易于解释的模型。
LASSO回归的缺点:
- 当数据集中存在高度相关的特征时,LASSO回归倾向于选择其中一个特征,并将其他高度相关的特征系数缩减为零,导致模型的稳定性下降。
- LASSO回归在特征选择过程中可能会受到数据集中噪声的影响,选择不正确的特征。
6.6 弹性网络回归 Elastic Net:
综合了上述两种回归方法的优缺点,系数平方和与绝对值累计和同时存在于目标函数中,为了调和误差与系数绝对值累计和、系数平方和三者对损失函数的影响程度,引入了两个超参数和
弹性网络回归 Elastic Net 同时使用L1范数和L2范数的正则化项,可以在特征选择和模型稳定性之间找到平衡。
弹性网络回归的优点包括:
- 能够处理具有共线性的数据,并减少过拟合的风险。
- 同时具备特征选择的能力,可以将某些不相关的特征的系数缩减为零。
- 对于存在高度相关特征的情况,弹性网络回归可以更稳定地选择相关特征,并在相关特征之间进行均匀的分配。
然而,弹性网络回归也有一些缺点:
- 在具有大量特征的数据集中,计算复杂度较高,尤其是当数据集的维度非常高时。
- 对于某些问题,弹性网络回归可能不如岭回归或LASSO回归单独应用效果好。
7 实战一(线性回归拟合):
7.1 目的:
在给定的曲线特征数据集上使用线性回归模型进行拟合,并观察线性回归对于曲线数据的拟合效果。
7.2 步骤:
- 生成曲线特征数据集
x
和目标变量y
。- 使用线性回归模型对数据进行拟合,但由于线性回归无法拟合曲线特征,拟合结果不理想。
- 增加一个特征,将原始特征
x
和其平方x**2
进行堆叠,得到特征矩阵X2
。- 使用增加特征后的线性回归模型对数据进行拟合,可以更好地拟合曲线特征数据。
- 绘制原始数据散点图和拟合结果曲线。
7.3 代码:
import numpy as np
import matplotlib.pyplot as plt
# 曲线特征数据集
x = np.random.uniform(-3, 3, size=100)#生成一个包含100个随机数的一维数组 x,从均匀分布的区间 [-3, 3) 中抽取的
X = x.reshape(-1, 1)#转化为100*1的形状,将行向量转为列向量
# 一元二次方程
y = 0.5 * x**2 + x + 2 + np.random.normal(0, 1, 100)
plt.scatter(x, y)
plt.show()
# 使用线性回归无法拟合曲线特征数据
from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X, y)
y_predict = lin_reg.predict(X)
plt.scatter(x, y)
plt.plot(x, y_predict, color='r')
plt.show()
# 增加一个特征可以更好的拟合数据
X2 = np.hstack([X, X**2])#将两个数组水平堆叠在一起,生成一个新的二维数组 X2。
lin_reg2 = LinearRegression()
lin_reg2.fit(X2, y)
y_predict2 = lin_reg2.predict(X2)
plt.scatter(x, y)
# 由于x是乱的,所以应该进行排序
# np.sort(x) 用于对数组 x 进行排序,返回一个按升序排列的新数组。
# np.argsort(x) 返回的是对 x 进行排序后的索引数组。
# 这两个操作的目的是使得 x 和 y_predict2 的值按照 x 的升序排列,以便在绘图时能够正确地连接数据点。
plt.plot(np.sort(x), y_predict2[np.argsort(x)], color='r')
plt.show()
# 第一个系数是x前面的系数,第二个系数是x平方前面的系数
print(lin_reg2.coef_)
print(lin_reg2.intercept_)#偏置
8 实战二(过拟合与欠拟合):
8.1 目的:
在给定的曲线特征数据集上使用多项式回归模型进行拟合,并观察不同多项式阶数对于数据拟合的效果。
8.2 步骤:
- 生成曲线特征数据集
x
,并通过一元二次方程生成对应的目标变量y
。这里的目标变量y
是由一元二次方程生成的,还叠加了服从正态分布的随机噪声。- 绘制原始数据的散点图,展示数据的分布情况。
- 使用线性回归模型进行拟合,即使用一阶多项式进行拟合。绘制拟合结果曲线,并计算线性回归模型在训练数据上的均方误差。
- 定义了一个函数
PolynomialRegression(degree)
,用于创建一个多项式回归模型的管道(Pipeline)。管道中包含了多项式特征转换、特征缩放和线性回归三个步骤。- 使用二阶多项式回归模型进行拟合,通过管道进行特征转换和线性回归拟合。绘制拟合结果曲线,并计算二阶多项式回归模型在训练数据上的均方误差。
- 使用十阶和一百阶多项式回归模型进行拟合,并分别绘制拟合结果曲线和计算均方误差。
- 最后,打印出不同多项式阶数的多项式回归模型在训练数据上的均方误差。
8.3 代码:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error
# 曲线特征数据集
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, 100)
plt.scatter(x, y)
plt.show()
# 线性回归(欠拟合)
from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X, y)
y_predict = lin_reg.predict(X)
plt.scatter(x, y)
plt.plot(x, y_predict, color='r')
plt.show()
print('均方误差为:',mean_squared_error(y, y_predict))
# 增加一个特征可以更好的拟合数据
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
def PolynomialRegression(degree):
return Pipeline([
("poly", PolynomialFeatures(degree=degree)),
("std_scaler", StandardScaler()),#将特征的值按照均值为0、标准差为1的标准正态分布进行缩放,有助于避免某些特征在模型训练中过于主导
("lin_reg", LinearRegression())
])
#使用二项式
poly2_reg = PolynomialRegression(degree=2)
poly2_reg.fit(X, y)
y2_predict = poly2_reg.predict(X)
print('均方误差为:',mean_squared_error(y, y2_predict))
plt.scatter(x, y)
plt.plot(np.sort(x), y2_predict[np.argsort(x)], color='r')
plt.show()
# 使用十项式
poly10_reg = PolynomialRegression(degree=10)
poly10_reg.fit(X, y)
y10_predict = poly10_reg.predict(X)
print('均方误差为:',mean_squared_error(y, y10_predict))
plt.scatter(x, y)
plt.plot(np.sort(x), y10_predict[np.argsort(x)], color='r')
plt.show()
# 使用一百项式
poly100_reg = PolynomialRegression(degree=100)
poly100_reg.fit(X, y)
y100_predict = poly100_reg.predict(X)
print('均方误差为:',mean_squared_error(y, y100_predict))
plt.scatter(x, y)
plt.plot(np.sort(x), y100_predict[np.argsort(x)], color='r')
plt.show()
9 实战三(学习曲线):
9.1 目的:
在给定的曲线特征数据集上使用线性回归和多项式回归模型进行拟合,并绘制它们的学习曲线,以观察模型在不同样本数量下的性能变化。
9.2 步骤:
- 生成曲线特征数据集
x
和目标变量y
。x
是在 -3.0 到 3.0 之间均匀分布的随机数,y
是由一元二次方程生成的,并添加服从正态分布的随机噪声。- 绘制原始数据的散点图,展示数据的分布情况。
- 将数据集划分为训练集和测试集。
- 定义了一个函数
plot_learning_curve(algo, X_train, X_test, y_train, y_test)
,用于绘制学习曲线。该函数接受一个算法或模型algo
,训练集和测试集的特征数据X_train
、X_test
,以及训练集和测试集的目标变量数据y_train
、y_test
。- 在
plot_learning_curve
函数中,使用循环逐步增加训练样本数量,对算法或模型进行训练和预测,并计算训练集和测试集的均方误差。将均方误差存储在train_score
和test_score
列表中。- 绘制学习曲线,横坐标为样本数量,纵坐标为均方根误差(RMSE),分别表示训练集和测试集的误差随样本数量的变化情况。
- 调用
plot_learning_curve
函数,传入线性回归模型和训练集、测试集的数据,绘制线性回归的学习曲线。- 定义了一个多项式回归模型的函数
PolynomialRegression(degree)
,通过管道(Pipeline)包含多项式特征转换、特征缩放和线性回归三个步骤。- 调用
PolynomialRegression(degree=2)
,生成一个二阶多项式回归模型,并使用该模型绘制学习曲线。- 调用
PolynomialRegression(degree=20)
,生成一个二十阶多项式回归模型,并使用该模型绘制学习曲线。
9.3 代码:
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)
plt.show()
# 随着训练数据的增多,观察误差的变化
# 线性回归
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=10)
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
def plot_learning_curve(algo, X_train, X_test, y_train, y_test):#algo:要评估的算法或模型。
train_score = []#用于存储每个样本数量下的训练集和测试集的均方误差。
test_score = []
for i in range(1, len(X_train)+1):#在每个循环迭代中,使用部分训练数据(逐步增加)对模型进行拟合
algo.fit(X_train[:i], y_train[:i])
y_train_predict = algo.predict(X_train[:i])
train_score.append(mean_squared_error(y_train[:i], y_train_predict))#将训练集和测试集的均方误差分别添加到 train_score 和 test_score 列表中。
y_test_predict = algo.predict(X_test)
test_score.append(mean_squared_error(y_test, y_test_predict))
plt.plot([i for i in range(1, len(X_train)+1)],
np.sqrt(train_score), label="train")
plt.plot([i for i in range(1, len(X_train)+1)],
np.sqrt(test_score), label="test")
plt.legend()#在图表中显示图例
plt.axis([0, len(X_train)+1, 0, 4])#用于设置坐标轴的范围
plt.show()
plot_learning_curve(LinearRegression(), X_train, X_test, y_train, y_test)#显示线性回归的学习曲线
# 多项式回归(二项)
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
def PolynomialRegression(degree):
return Pipeline([
("poly", PolynomialFeatures(degree=degree)),
("std_scaler", StandardScaler()),#将特征的值按照均值为0、标准差为1的标准正态分布进行缩放,有助于避免某些特征在模型训练中过于主导
("lin_reg", LinearRegression())
])
poly2_reg = PolynomialRegression(degree=2)#设置多项式为2项
plot_learning_curve(poly2_reg, X_train, X_test, y_train, y_test)
# 多项式回归(20项)
poly20_reg = PolynomialRegression(degree=20)#设置多项式为20项
plot_learning_curve(poly20_reg, X_train, X_test, y_train, y_test)
10 实战四( 岭回归):
10.1 目的:
在给定的曲线特征数据集上使用多项式回归和岭回归模型进行拟合,并评估它们在不同的岭回归超参数下的性能
10.2 步骤:
- 生成曲线特征数据集
x
和目标变量y
。x
是在 -3.0 到 3.0 之间均匀分布的随机数,y
是由线性方程生成的,并添加服从正态分布的随机噪声。- 绘制原始数据的散点图,展示数据的分布情况。
- 定义了一个多项式回归模型的函数
PolynomialRegression(degree)
,通过管道(Pipeline)包含多项式特征转换、特征缩放和线性回归三个步骤。- 将数据集划分为训练集和测试集。
- 实例化一个多项式回归模型
poly_reg
,使用二十阶多项式进行拟合,并对测试集进行预测。- 计算预测值与实际值之间的均方误差,并打印输出。
- 生成用于绘制拟合曲线的数据
X_plot
,并使用训练好的多项式回归模型对其进行预测,得到y_plot
。- 绘制原始数据的散点图和多项式回归的拟合曲线。
- 定义了一个岭回归模型的函数
RidgeRegression(degree, alpha)
,通过管道(Pipeline)包含多项式特征转换、特征缩放和岭回归三个步骤。- 定义了一个辅助函数
plot_model(model)
,用于绘制岭回归模型的拟合曲线。- 实例化一个岭回归模型
ridge1_reg
,设置超参数 alpha 为 0.0001,并进行拟合和预测。- 计算预测值与实际值之间的均方误差,并打印输出。
- 使用辅助函数
plot_model
绘制岭回归模型的拟合曲线。- 重复步骤 11-13,分别设置不同的超参数 alpha(1、100、10000000)进行岭回归拟合和评估。
- 通过绘制拟合曲线和计算均方误差,观察不同 alpha 值对岭回归模型的影响。
10.3 代码:
import numpy as np
import matplotlib.pyplot as plt
# 曲线特征数据集
np.random.seed(42)
x = np.random.uniform(-3.0, 3.0, size=100)
X = x.reshape(-1, 1)
y = 0.5 * x + 3 + np.random.normal(0, 1, size=100)
plt.scatter(x, y)
plt.show()
# 多项式回归
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
def PolynomialRegression(degree):
return Pipeline([
("poly", PolynomialFeatures(degree=degree)),
("std_scaler", StandardScaler()),
("lin_reg", LinearRegression())
])
from sklearn.model_selection import train_test_split
np.random.seed(666)
X_train, X_test, y_train, y_test = train_test_split(X, y)
from sklearn.metrics import mean_squared_error
poly_reg = PolynomialRegression(degree=20)
poly_reg.fit(X_train, y_train)
y_poly_predict = poly_reg.predict(X_test)
print(mean_squared_error(y_test, y_poly_predict))
X_plot = np.linspace(-3, 3, 100).reshape(100, 1)
y_plot = poly_reg.predict(X_plot)
plt.scatter(x, y)
plt.plot(X_plot[:,0], y_plot, color='r')
plt.axis([-3, 3, 0, 6])
plt.show()
# 岭回归 α=0.0001
from sklearn.linear_model import Ridge
def RidgeRegression(degree, alpha):
return Pipeline([
("poly", PolynomialFeatures(degree=degree)),
("std_scaler", StandardScaler()),
("ridge_reg", Ridge(alpha=alpha))
])
def plot_model(model):
X_plot = np.linspace(-3, 3, 100).reshape(100, 1)
y_plot = model.predict(X_plot)
plt.scatter(x, y)
plt.plot(X_plot[:,0], y_plot, color='r')
plt.axis([-3, 3, 0, 6])
plt.show()
ridge1_reg = RidgeRegression(20, 0.0001)
ridge1_reg.fit(X_train, y_train)
y1_predict = ridge1_reg.predict(X_test)
print(mean_squared_error(y_test, y1_predict))
plot_model(ridge1_reg)
# 岭回归 α=1
ridge2_reg = RidgeRegression(20, 1)
ridge2_reg.fit(X_train, y_train)
y2_predict = ridge2_reg.predict(X_test)
print(mean_squared_error(y_test, y2_predict))
plot_model(ridge2_reg)
# 岭回归 α=100
ridge3_reg = RidgeRegression(20, 100)
ridge3_reg.fit(X_train, y_train)
y3_predict = ridge3_reg.predict(X_test)
print(mean_squared_error(y_test, y3_predict))
plot_model(ridge3_reg)
# 岭回归 α=10000000
ridge4_reg = RidgeRegression(20, 10000000)
ridge4_reg.fit(X_train, y_train)
y4_predict = ridge4_reg.predict(X_test)
print(mean_squared_error(y_test, y4_predict))
plot_model(ridge4_reg)
结果图示参见上文。
11 实战五( LASSO回归):
11.1 目的:
在给定的曲线特征数据集上使用多项式回归和LASSO回归模型进行拟合,并评估它们在不同的LASSO回归超参数下的性能。
11.2 步骤:
- 生成曲线特征数据集
x
和目标变量y
。x
是在 -3.0 到 3.0 之间均匀分布的随机数,y
是由线性方程生成的,并添加服从正态分布的随机噪声。- 绘制原始数据的散点图,展示数据的分布情况。
- 定义了一个多项式回归模型的函数
PolynomialRegression(degree)
,通过管道(Pipeline)包含多项式特征转换、特征缩放和线性回归三个步骤。- 将数据集划分为训练集和测试集。
- 实例化一个多项式回归模型
poly_reg
,使用二十阶多项式进行拟合,并对测试集进行预测。- 计算预测值与实际值之间的均方误差,并打印输出。
- 生成用于绘制拟合曲线的数据
X_plot
,并使用训练好的多项式回归模型对其进行预测,得到y_plot
。- 绘制原始数据的散点图和多项式回归的拟合曲线。
- 定义了一个LASSO回归模型的函数
LassoRegression(degree, alpha)
,通过管道(Pipeline)包含多项式特征转换、特征缩放和LASSO回归三个步骤。- 定义了一个辅助函数
plot_model(model)
,用于绘制LASSO回归模型的拟合曲线。- 实例化一个LASSO回归模型
lasso1_reg
,设置超参数 alpha 为 0.01,并进行拟合和预测。- 计算预测值与实际值之间的均方误差,并打印输出。
- 使用辅助函数
plot_model
绘制LASSO回归模型的拟合曲线。- 重复步骤 11-13,分别设置不同的超参数 alpha(0.1、1)进行LASSO回归拟合和评估。
- 通过绘制拟合曲线和计算均方误差,观察不同 alpha 值对LASSO回归模型的影响。
11.3 代码:
import numpy as np
import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
# 曲线特征数据集
np.random.seed(42)
x = np.random.uniform(-3.0, 3.0, size=100)
X = x.reshape(-1, 1)
y = 0.5 * x + 3 + np.random.normal(0, 1, size=100)
plt.scatter(x, y)
plt.show()
# 多项式回归
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
def PolynomialRegression(degree):
return Pipeline([
("poly", PolynomialFeatures(degree=degree)),
("std_scaler", StandardScaler()),
("lin_reg", LinearRegression())
])
from sklearn.model_selection import train_test_split
np.random.seed(666)
X_train, X_test, y_train, y_test = train_test_split(X, y)
from sklearn.metrics import mean_squared_error
poly_reg = PolynomialRegression(degree=20)
poly_reg.fit(X_train, y_train)
y_poly_predict = poly_reg.predict(X_test)
print(mean_squared_error(y_test, y_poly_predict))
X_plot = np.linspace(-3, 3, 100).reshape(100, 1)
y_plot = poly_reg.predict(X_plot)
plt.scatter(x, y)
plt.plot(X_plot[:,0], y_plot, color='r')
plt.axis([-3, 3, 0, 6])
plt.show()
# LASSO回归 α=0.01
from sklearn.linear_model import Lasso
def LassoRegression(degree, alpha):
return Pipeline([
("poly", PolynomialFeatures(degree=degree)),
("std_scaler", StandardScaler()),
("lasso_reg", Lasso(alpha=alpha))
])
def plot_model(model):
X_plot = np.linspace(-3, 3, 100).reshape(100, 1)
y_plot = model.predict(X_plot)
plt.scatter(x, y)
plt.plot(X_plot[:,0], y_plot, color='r')
plt.axis([-3, 3, 0, 6])
plt.show()
lasso1_reg = LassoRegression(20, 0.01)
lasso1_reg.fit(X_train, y_train)
y1_predict = lasso1_reg.predict(X_test)
print(mean_squared_error(y_test, y1_predict))
plot_model(lasso1_reg)
# LASSO回归 α=0.1
lasso2_reg = LassoRegression(20, 0.1)
lasso2_reg.fit(X_train, y_train)
y2_predict = lasso2_reg.predict(X_test)
print(mean_squared_error(y_test, y2_predict))
plot_model(lasso2_reg)
# LASSO回归 α=1
lasso3_reg = LassoRegression(20, 1)
lasso3_reg.fit(X_train, y_train)
y3_predict = lasso3_reg.predict(X_test)
print(mean_squared_error(y_test, y3_predict))
plot_model(lasso3_reg)
结果图示参见上文。