从0开始机器学习--5.正则化技术(含代码)

写在前面

在整个第四篇中,我们已经掌握了八大基础的机器学习模型,但是我们留了一个不断强调的疑问--什么是正则化?在这一篇博客中,我们就一起来了解L1、L2正则化技术。

1.python基础;
2.ai模型概念+基础;
3.数据预处理;
4.机器学习模型--1.聚类;2.降维;3.回归(预测);4.分类;
5.正则化技术;
6.神经网络模型--1.概念+基础;2.几种常见的神经网络模型;
7.对回归、分类模型的评价方式;
8.简单强化学习概念;
9.几种常见的启发式算法及应用场景;
10.机器学习延申应用-数据分析相关内容--1.A/B Test;2.辛普森悖论;3.蒙特卡洛模拟;
以及其他的与人工智能相关的学习经历,如数据挖掘、计算机视觉-OCR光学字符识别等。


本文目录

写在前面

正则化

L1正则化(Lasso Regularization)

Lasso线性回归模型

代码

L2正则化(Ridge Regularization)

代码

Elastic Net(L1 + L2)

为什么用正则化

L1 v.s L2

什么时候使用L1、L2正则化

总结


正则化

正则化是为了防止机器学习模型过拟合(《4.4分类-决策树部分》有详细解释)的一种方法,主要通过向损失函数中添加惩罚项来约束模型参数的大小,从而控制模型的复杂度。

L1正则化(Lasso Regularization)

L1 正则化通过在损失函数中添加参数绝对值的和来约束模型参数。L1 正则化可以产生稀疏解,即它会将一些不重要的特征的权重缩减为零,从而进行特征选择。

L1正则化通过惩罚模型的系数绝对值来防止过拟合。L1正则化项添加到损失函数中:

$\text{Loss} = \sum_{i=1}^{n} (y_i - \hat{y_i})^2 + \lambda \sum_{j=1}^{p} |\beta_j|$

其中,\lambda 是正则化强度,\beta_j 是模型的系数。

Lasso线性回归模型

相比 sklearn.linear_model.LinearRegression 的主要区别在于 Lasso 回归引入了 L1 正则化,这使得 Lasso 回归在处理线性回归问题时具有自动特征选择的能力。而 LinearRegression 是标准的线性回归,不包括任何正则化项。

代码

我们可以生成一个包含多重共线性和一些不相关特征的合成数据集。这样,Lasso回归能够通过正则化减少不相关特征的影响,同时保持重要特征的系数。

以下是一个示例代码,它创建了一个具有相关特征的数据集,并比较线性回归和Lasso回归的效果:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import Lasso, LinearRegression
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split

# 生成数据
np.random.seed(42)
n_samples = 1000
n_features = 10

# 生成线性关系
X, y, coefficients = make_regression(n_samples=n_samples, n_features=n_features, noise=0.1, coef=True)

# 引入多重共线性
X[:, 1] = X[:, 0] + np.random.normal(0, 0.1, n_samples)  # 使第二个特征与第一个特征高度相关
X[:, 2] = X[:, 0] + np.random.normal(0, 0.1, n_samples)  # 使第三个特征与第一个特征高度相关

# 添加一些不相关特征
X[:, 3:] = np.random.normal(0, 1, size=(n_samples, n_features - 3))

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建线性回归模型
linear_model = LinearRegression()
linear_model.fit(X_train, y_train)

# 创建Lasso回归模型 (L1正则化)
lasso = Lasso(alpha=0.1)  # alpha 是正则化强度 λ
lasso.fit(X_train, y_train)

# 打印结果
print("Linear Regression coefficients:", linear_model.coef_)
print("Lasso coefficients:", lasso.coef_)
print("Linear Regression Train score:", linear_model.score(X_train, y_train))
print("Lasso Train score:", lasso.score(X_train, y_train))
print("Linear Regression Test score:", linear_model.score(X_test, y_test))
print("Lasso Test score:", lasso.score(X_test, y_test))

# 可视化系数对比
plt.figure(figsize=(10, 5))
indices = np.arange(len(linear_model.coef_))
bar_width = 0.35

# 绘制条形图
plt.bar(indices, linear_model.coef_, width=bar_width, label='Linear Regression Coefficients', alpha=0.6, color='blue')
plt.bar(indices + bar_width, lasso.coef_, width=bar_width, label='Lasso Coefficients', alpha=0.6, color='orange')

plt.axhline(0, color='black', lw=0.8, ls='--')
plt.title('Comparison of Coefficients with Multicollinearity')
plt.xlabel('Feature Index')
plt.ylabel('Coefficient Value')
plt.xticks(indices + bar_width / 2, range(len(linear_model.coef_)))
plt.legend()
plt.show()

输出:

Linear Regression coefficients: [-10.17878777 -18.8479344   53.49287804  -3.52525877   3.79833395
  -2.42438072   3.28082074   3.87251837  -3.64721889  -4.03141021]
Lasso coefficients: [ -0.         -13.8387546   38.39331588  -3.41534393   3.70966158    
  -2.36004952   3.2199666    3.83057071  -3.5982013   -3.93762051]
Linear Regression Train score: 0.04260312671341826
Lasso Train score: 0.04245550209441307
Linear Regression Test score: 0.014397173560824372
Lasso Test score: 0.01713562881207298
  • 从Lasso的系数来看,第二个特征(-13.84)和第三个特征(38.39)的影响较大,因此可以认为它们是重要特征。而第一个特征被认为是不重要的。
  • 在Lasso模型中,正负系数指示了特征对目标变量的影响方向:正值表示正向影响,负值表示负向影响。

从图中我们可以很清晰的看到,因为index为1和2的特征都与index为0的特征有高相关性,所以L1正则化技术将他们两个的系数减小了。这也体现在回归任务的准确率上。

L2正则化(Ridge Regularization)

L2 正则化通过在损失函数中添加参数平方的和来约束模型参数。L2 正则化不会产生稀疏解,而是将所有权重缩小。它常用于防止模型对数据中的噪声过于敏感

L2正则化通过惩罚模型的系数平方来防止过拟合。L2正则化项为:

\text{Loss} = \sum_{i=1}^{n} (y_i - \hat{y_i})^2 + \lambda \sum_{j=1}^{p} \beta_j^2

代码

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import Ridge, LinearRegression
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split

# 生成数据
np.random.seed(42)
n_samples = 200
n_features = 10

# 生成线性关系
X, y, coefficients = make_regression(n_samples=n_samples, n_features=n_features, noise=0.1, coef=True)

# 引入多重共线性
X[:, 1] = X[:, 0] + np.random.normal(0, 0.1, n_samples)  # 使第二个特征与第一个特征高度相关
X[:, 2] = X[:, 0] + np.random.normal(0, 0.1, n_samples)  # 使第三个特征与第一个特征高度相关

# 添加一些不相关特征
X[:, 3:] = np.random.normal(0, 1, size=(n_samples, n_features - 3))

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建线性回归模型
linear_model = LinearRegression()
linear_model.fit(X_train, y_train)

# 创建Ridge回归模型 (L2正则化)
ridge = Ridge(alpha=1.0)  # alpha 是正则化强度 λ
ridge.fit(X_train, y_train)

# 打印结果
print("Linear Regression coefficients:", linear_model.coef_)
print("Ridge coefficients:", ridge.coef_)
print("Linear Regression Train score:", linear_model.score(X_train, y_train))
print("Ridge Train score:", ridge.score(X_train, y_train))
print("Linear Regression Test score:", linear_model.score(X_test, y_test))
print("Ridge Test score:", ridge.score(X_test, y_test))

# 可视化系数对比
plt.figure(figsize=(10, 5))
indices = np.arange(len(linear_model.coef_))
bar_width = 0.35

# 绘制条形图
plt.bar(indices, linear_model.coef_, width=bar_width, label='Linear Regression Coefficients', alpha=0.6, color='blue')
plt.bar(indices + bar_width, ridge.coef_, width=bar_width, label='Ridge Coefficients', alpha=0.6, color='orange')

plt.axhline(0, color='black', lw=0.8, ls='--')
plt.title('Comparison of Coefficients with Multicollinearity (L2 Regularization)')
plt.xlabel('Feature Index')
plt.ylabel('Coefficient Value')
plt.xticks(indices + bar_width / 2, range(len(linear_model.coef_)))
plt.legend()
plt.show()

输出:

Linear Regression coefficients: [ 210.92262166 -139.42530133  -24.53875229    0.95538475   -0.96199276
   13.81632524   -2.27305575   20.28506279    0.21798891   12.86490434]
Ridge coefficients: [ 83.41761334 -54.84349285  16.84318549   0.22853894  -1.6074608     
  14.77324996  -2.47395192  21.11750683  -0.16362683  11.92624379]
Linear Regression Train score: 0.10322971033165995
Ridge Train score: 0.10012293620737911
Linear Regression Test score: 0.021651598639087055
Ridge Test score: 0.03320967861677293
  • 系数变化

    • 线性回归的系数显示出非常大的值(如210.92和-139.43),这可能是由于多重共线性导致的不稳定性
    • Ridge回归的系数较小且更加平滑,这表明正则化减少了模型的复杂性,使得模型更为稳健,能够更好地应对多重共线性的问题。
  • 训练和测试得分

    • 两个模型的训练得分相对接近,但都不高,这表明模型在训练集上都没有充分捕捉到数据的规律。
    • 测试得分显示Ridge回归模型在测试集上的表现(0.0332)优于线性回归(0.0217),这表明Ridge模型在泛化能力上可能更好,特别是在面对新数据时。
  • 正则化的效果

    • 通过比较可以看出,Ridge回归能够抑制过拟合,提高模型的泛化能力。这在实际应用中非常重要,尤其是当特征数目较多且可能存在冗余信息时。

Elastic Net(L1 + L2)

通过生成具有一定噪声的数据,可以观察不同正则化方法对模型性能和系数的影响。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression, Lasso, Ridge, ElasticNet
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split

# 生成数据
np.random.seed(42)
X, y = make_regression(n_samples=100, n_features=10, noise=10)  # 增加噪声以突出效果

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 线性回归
linear_reg = LinearRegression()
linear_reg.fit(X_train, y_train)

# Lasso回归 (L1正则化)
lasso = Lasso(alpha=0.1)
lasso.fit(X_train, y_train)

# Ridge回归 (L2正则化)
ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)

# ElasticNet回归 (L1 + L2正则化)
elastic_net = ElasticNet(alpha=0.1, l1_ratio=0.5)  # l1_ratio 控制 L1 和 L2 的比例
elastic_net.fit(X_train, y_train)

# 打印结果
print("Linear Regression coefficients:", linear_reg.coef_)
print("Lasso coefficients:", lasso.coef_)
print("Ridge coefficients:", ridge.coef_)
print("ElasticNet coefficients:", elastic_net.coef_)

print("Linear Regression Train score:", linear_reg.score(X_train, y_train))
print("Lasso Train score:", lasso.score(X_train, y_train))
print("Ridge Train score:", ridge.score(X_train, y_train))
print("ElasticNet Train score:", elastic_net.score(X_train, y_train))

print("Linear Regression Test score:", linear_reg.score(X_test, y_test))
print("Lasso Test score:", lasso.score(X_test, y_test))
print("Ridge Test score:", ridge.score(X_test, y_test))
print("ElasticNet Test score:", elastic_net.score(X_test, y_test))

# 可视化结果
plt.figure(figsize=(12, 6))
plt.plot(range(len(linear_reg.coef_)), linear_reg.coef_, label='Linear Regression', marker='o')
plt.plot(range(len(lasso.coef_)), lasso.coef_, label='Lasso', marker='o')
plt.plot(range(len(ridge.coef_)), ridge.coef_, label='Ridge', marker='o')
plt.plot(range(len(elastic_net.coef_)), elastic_net.coef_, label='ElasticNet', marker='o')
plt.xlabel('Feature Index')
plt.ylabel('Coefficient Value')
plt.title('Comparison of Coefficients for Different Models')
plt.legend()
plt.grid()
plt.show()

输出:

Linear Regression coefficients: [19.04601535 54.9486047   3.58197804 63.70272898 92.80875602 69.57689675
 84.54229532  8.66095516  2.98804205 71.1881188 ]
Lasso coefficients: [18.96025415 54.8553183   3.43132401 63.6082866  92.65442432 69.48209529
 84.42789762  8.49332936  2.90087787 71.0628166 ]
Ridge coefficients: [19.18928993 54.03791934  3.58580842 62.75934219 91.36596764 68.66297355
 83.5355643   8.17128047  3.08538397 69.92804885]
ElasticNet coefficients: [19.47382004 51.42065912  3.53140627 60.05991178 87.23743422 66.00975654
 80.61835736  6.75445054  3.29296142 66.35743168]
Linear Regression Train score: 0.9969101159920114
Lasso Train score: 0.9969062683779599
Ridge Train score: 0.9967140162982814
ElasticNet Train score: 0.9939636276755514
Linear Regression Test score: 0.9982923687146219
Lasso Test score: 0.9982545174239741
Ridge Test score: 0.9978774507478436
ElasticNet Test score: 0.9945289095903181

在这组数据的示例中,从预测拟合准确性的角度,确实是简单的线性回归模型做的更好。但是所有模型的训练分数和测试分数都非常高,表明它们能够很好地拟合数据,并且泛化性能也较好。从准确性(测试分数)高低的层次来说:

  • 正则化模型(Lasso、Ridge、ElasticNet)略低一点。这通常是因为正则化模型通过引入惩罚项来防止过拟合
  • ElasticNet的训练和测试分数略低于其他模型,表明它对数据进行了更多的约束。这可能是因为ElasticNet结合了L1和L2正则化,更多地平衡了特征选择和模型复杂性。
  • ElasticNet的系数变化最明显,这表明它不仅平滑了系数,还减少了一些不太重要的特征对模型的影响,从而提升模型的稳定性。

 

为什么用正则化

  1. 防止过拟合:当模型过于复杂时,容易对训练数据中的噪声进行拟合,导致泛化能力差。正则化通过限制模型参数的大小,控制模型的复杂度,减少过拟合的可能性。
  2. 增强模型的泛化能力:正则化能够使得模型在测试集上的表现更加稳定,提高模型的泛化能力。

L1 v.s L2

  • L1 正则化:倾向于产生稀疏解,使得部分特征的权重为零。因此,它可以用于特征选择,即识别出哪些特征是重要的。
  • L2 正则化:倾向于将所有特征的权重缩小到接近于零,而不是完全为零。它通常用于防止参数过大,从而避免模型对数据中的噪声过于敏感

什么时候使用L1、L2正则化

  • L1 正则化:适用于高维数据(特征数远大于样本数)的场景,或者当希望进行特征选择时使用。
  • L2 正则化:适用于特征数量较多且不希望将权重完全归零的场景,常用于防止模型过度拟合。
  • Elastic Net(L1 + L2):当你希望结合L1和L2正则化的优势时,可以使用Elastic Net,这是一种同时使用L1和L2正则化的方式。

正则化通常用于线性模型(如线性回归、逻辑回归),通过将正则化项添加到损失函数中实现。它本身不是学习算法,只是控制模型复杂度的手段。常见的监督学习模型包括线性回归、逻辑回归、支持向量机等,这些模型中的参数可能会通过 L1 或 L2 正则化来控制。在一些无监督学习任务(如稀疏编码、主成分分析(PCA)等)中,也可以使用正则化技术。正则化可以帮助模型减少对数据噪声的敏感性,或者通过稀疏性获得更有意义的表示。例如,稀疏PCA中可以使用L1正则化来得到稀疏的主成分


总结

正则化通过在损失函数中添加惩罚项来控制模型复杂度,防止过拟合并提高模型泛化能力。L1 正则化(如 Lasso)倾向于产生稀疏解,适合特征选择。L2 正则化(如 Ridge)则会缩小所有特征权重,减少对噪声的敏感性。Elastic Net 结合了 L1 和 L2 的优势,既能特征选择,又能控制权重大小。正则化在高维数据中尤其有用,常用于线性回归、逻辑回归等模型,提高模型在未知数据上的表现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值