关于线性回归的原理,详细可以参考我写的这篇博客:机器学习算法2-线性回归-原理
1.使用正规方程进行求解
正规方程(Normal Equation)是一种用于求解线性回归模型中参数(\(\theta\))的解析方法。与梯度下降等迭代优化算法不同,正规方程可以直接一步到位地计算出使成本函数/损失函数(Cost Function)最小化的最优参数。
准备真实数据,绘制散点图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 结果可以被复现
np.random.seed(42)
# 生成数据
X = np.linspace(0, 10, 30).reshape(-1, 1)
# 斜率和截距随机生成
true_w = np.random.randint(1, 5, size=1)
true_b = np.random.randint(1, 10, size=1)
# 根据一元一次方程计算目标y, 并且加上噪声
y = X * true_w + true_b + np.random.randn(30, 1)
# 绘制散点图
plt.figure(figsize=(10, 8))
plt.scatter(X, y, label="原始数据点")
plt.xlabel("特征X")
plt.ylabel("目标值")
plt.grid()
plt.show()
display(f"斜率:{true_w}, 截距:{true_b}")
‘
使用正规方程求解之前,需要进行处理:为X添加一列1, 用于求解b,原因如下:
1
X_b = np.concatenate([np.full(shape=(30, 1), fill_value=1), X], axis=1)
然后根据正规方程公式计算:
1
2
3
theta = np.linalg.inv(X_b.T@X_b)@(X_b.T)@y
w_ = theta[1, 0]
b_ = theta[0, 0]
绘制回归线:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 绘制散点图
plt.figure(figsize=(10, 8))
plt.scatter(X, y, label="原始数据点")
plt.xlabel("特征X")
plt.ylabel("目标值")
plt.grid()
# 绘制回归线
x_plot = np.array([X.min(), X.max()]).reshape(-1, 1)
y_plot = w_ * x_plot + b_
plt.plot(x_plot, y_plot, c="red", lw=1.5, label="正规方程回归线")
plt.legend()
plt.show()
# display(f"斜率:{true_w}, 截距:{true_b}")
选择题:
-
正规方程求解线性回归参数时,主要缺点是什么?
A. 需要选择合适的学习率
B. 当特征数量非常大时,计算速度慢
C. 只能用于简单线性回归,不能用于多元线性回归
D. 无法保证找到最优解
答案:B,正规方程的计算复杂度主要来源于矩阵求逆,为 \(O(n^3)\),其中 n 是特征数量。当 n 很大时,这个计算量会变得非常大,因此计算速度慢是其主要缺点。A是梯度下降的缺点;C和D是错误的,正规方程可以用于多元回归且能找到全局最优解。
编程题: 请根据下面的数据,使用正规方程求解线性回归参数,并绘制回归线。 X = np.array([1, 2, 3, 4, 5, 6]).reshape(-1, 1)
y = np.array([3, 5, 7, 9, 11, 13]).reshape(-1, 1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
theta = np.linalg.inv(X_b.T@X_b)@(X_b.T)@y
w_ = theta[0, 0]
b_ = theta[1, 0]
# 画图
# 散点图
plt.figure(figsize=(10, 8), dpi=200)
plt.scatter(X, y, label="原始数据点")
plt.xlabel("特征X")
plt.ylabel("目标值")
# 回归线
X_plot = np.linspace(X.min(), X.max(), 10).reshape(-1, 1)
y_pred = X_plot * w_ + b_
plt.plot(X_plot, y_pred, c="purple", lw=1.5)
plt.grid()
plt.show()
2.多元线性回归 (二元一次方程)
多元线性回归模型可以表示为:\(y=\theta_0+\theta_1x_1+\theta_2x_2+\dots+\theta_nx_n\)
其矩阵形式与简单线性回归类似,但特征矩阵 X 会有更多的列。对于 m 个样本和 n 个特征,特征矩阵 X 的维度是\(m \times(n+1)\),其中第一列依然是全为1的项。参数\(\theta\) 的维度则是\((n+1)\times 1\)。
正规方程的公式在多元线性回归中依然适用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
from mpl_toolkits.mplot3d import Axes3D
np.random.seed(42)
X1 = np.random.randint(-150, 150, size=(200, 1))
X2 = np.random.randint(0, 300, size=(200, 1))
# 真实的截距和斜率
w_true = np.random.randint(1, 5, size=2)
b_true = np.random.randint(1, 10, size=1)
# 真实的y,加上一点噪声
y = w_true[0] * X1 + w_true[1] * X2 + b_true + np.random.randn(200, 1)
# 正规方程拟合,重新构造X,
X = np.concatenate([np.full(shape=(200, 1), fill_value=1), X1, X2], axis=1)
# 正规方程
theta = np.linalg.inv(X.T@X)@(X.T)@y
# 得到的theta是一个列向量,为了取出每个参数更方便,变成行向量
theta_solved = theta.reshape(-1)
print(f"真实截距:{b_true},预测的截距:{theta_solved[0]}, 真实的斜率:{w_true}, 预测的斜率:{theta_solved[1:]}")
fig = plt.figure(figsize=(10, 8), dpi=150)
# 创建3D Axes
ax3d = fig.add_subplot(111, projection="3d")
# 绘制三维散点图
scatter_3d = ax3d.scatter(
X1, X2, y,
alpha=0.7,
marker="o",
edgecolor="k",
lw=0.5,
depthshade=True,
label="原始数据"
)
# 画平面图的数据
x_plot = np.linspace(-150, 150, 10)
y_plot = np.linspace(0, 300, 10)
x_grid, y_grid = np.meshgrid(x_plot, y_plot)
Z = x_grid * theta_solved[1] + y_grid * theta_solved[2] + theta_solved[0]
ax3d.plot_surface(x_grid, y_grid, Z, color="lightgreen", alpha=0.5, label="正规方程回归平面")
# 设置3D轴标签
ax3d.set_xlabel("特征1", fontsize=12, color="red")
ax3d.set_ylabel("特征1", fontsize=12, color="green")
ax3d.set_zlabel("目标值", fontsize=12, color="blue", rotation=90)
# 添加标题和图例
ax3d.set_title("多元线性回归", fontsize=16)
ax3d.legend()
# 设置初始视角(可选)
ax3d.view_init(elev=20, azim=45)# 仰角和方位角
plt.tight_layout()
plt.savefig("./多元线性回归.pdf", dpi=150, facecolor="violet", edgecolor="navy", bbox_inches="tight", pad_inches = 0.1)
plt.show()
选择题:
-
对于一个有10000个样本,200个特征的多元线性回归问题,使用正规方程求解参数的计算复杂度量级大约是多少?
A. \(O(200^2)\)
B. \(O(10000^3)\)
C. \(O(200^3)\)
D. \(O(10000\times200)\)
答案:C,规方程的计算复杂度主要由\((X^TX)^{−1}\) 的求逆决定。X 的维度是 \(m \times(n+1)\),其中 m=10000,n=200。\(X^TX\) 的维度是 \((n+1)\times(n+1)\),即 \(201\times201\)。对这个矩阵求逆的复杂度是 \(O((n+1)^3)\),因此是 \(O(200^3)\) 量级。
编程题: 请创建一个有3个特征的多元线性回归数据集,并使用正规方程求解其参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from mpl_toolkits.mplot3d import Axes3D
np.random.seed(42)
X1 = np.random.randint(-150, 150, size=(200, 1))
X2 = np.random.randint(0, 300, size=(200, 1))
X3 = np.random.randint(300, 800, size=(200, 1))
# 真实的截距和斜率
w_true = np.random.randint(1, 5, size=3)
b_true = np.random.randint(1, 10, size=1)
# 真实的y,加上一点噪声
y = w_true[0] * X1 + w_true[1] * X2 + w_true[2] * X3 + b_true + np.random.randn(200, 1)
# 正规方程拟合,重新构造X,
X = np.concatenate([np.full(shape=(200, 1), fill_value=1), X1, X2, X3], axis=1)
# 正规方程
theta = np.linalg.inv(X.T@X)@(X.T)@y
# 得到的theta是一个列向量,为了取出每个参数更方便,变成行向量
theta_solved = theta.reshape(-1)
print(f"真实截距:{b_true},预测的截距:{theta_solved[0]}, 真实的斜率:{w_true}, 预测的斜率:{theta_solved[1:]}")
3.用 scikit-learn 实现线性回归
3.1scikit-learn 简介
scikit-learn
(通常缩写为 sklearn
) 是一个广泛使用的 Python 机器学习库,它提供了各种分类、回归、聚类和降维算法,以及用于模型选择和预处理的工具。其设计的核心理念是简洁、一致且易于使用。
- 统一的API:所有模型都遵循
fit()
和predict()
的统一接口,这使得模型之间可以轻松切换。 - 高效实现:底层使用 NumPy、SciPy 和 Cython 等库,确保了计算的高效性。
3.2scikit-learn 实现简单线性回归
scikit-learn
中的 LinearRegression
模型默认使用普通最小二乘法(OLS)来求解参数,其原理与正规方程相同,都是通过最小化均方误差来寻找最优解。然而,scikit-learn
的底层实现通常会采用更高效、数值更稳定的算法(例如奇异值分解 SVD),而不是直接计算矩阵逆。
LinearRegression
类的主要方法和属性:
fit(X, y)
: 训练模型,根据给定的训练数据X
和y
拟合模型。predict(X)
: 对新数据X
进行预测。coef_
: 训练后得到的系数(斜率),对应于 \(\theta_1,\theta_2,\dots,\theta_n\)。intercept_
: 训练后得到的截距,对应于 \(\theta_0\)。
看一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from sklearn.linear_model import LinearRegression
np.random.seed(42)
# 生成数据
X = np.random.randint(1, 10, 30).reshape(-1, 1)
true_w = np.random.randint(1, 5, size=1)
true_b = np.random.randint(1, 10, size=1)
y = X * true_w + true_b + np.random.randn(30, 1)
# 模型求解
model = LinearRegression()
model.fit(X, y)
w_ = model.coef_
b_ = model.intercept_
print(f"真实截距:{true_b},预测的截距:{b_}, 真实的斜率:{true_w}, 预测的斜率:{w_}")
# 画图
# 散点图
plt.figure(figsize=(10, 8), dpi=150)
plt.scatter(X, y, label ="原始数据点")
# 折线图
y_pred = model.predict(X)
plt.plot(X, y_pred, color="red", label="预测回归线")
plt.xlabel("特征")
plt.ylabel("值")
plt.title("sklearn实现简单线性回归")
plt.legend()
plt.tight_layout(pad=2)
plt.show()
选择题:
-
在
scikit-learn
中,如果要训练一个线性回归模型,哪一步是必不可少的?A. 导入
LinearRegression
类 B. 创建模型实例 C. 使用fit()
方法训练模型 D. 以上都正确
答案:D,训练一个
scikit-learn
模型的基本流程是:导入类、实例化模型、使用fit()
方法传入训练数据进行训练。
编程题: 使用 scikit-learn
的 LinearRegression
对给定的数据进行回归,并打印出模型的 R2 分数,以评估模型的好坏。 X = np.array([1, 2, 3, 4, 5, 6]).reshape(-1, 1)
y = np.array([3, 5, 7, 9, 11, 13]).reshape(-1, 1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
# 给定的数据
X = np.array([1, 2, 3, 4, 5, 6]).reshape(-1, 1)
y = np.array([3, 5, 7, 9, 11, 13]).reshape(-1, 1)
model = LinearRegression()
model.fit(X, y)
y_pred = model.predict(X)
r2 = r2_score(y, y_pred)
print(r2)
3.3scikit-learn 实现多元线性回归
scikit-learn
的 LinearRegression
类能够自动处理多元线性回归。用户只需将包含多个特征的矩阵 X
传入 fit()
方法即可。模型会自动拟合每个特征对应的系数(model.coef_
)和一个截距(model.intercept_
)。
model.coef_
会是一个数组,其长度与特征数量相等。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
from sklearn.metrics import r2_score
from sklearn.linear_model import LinearRegression
from mpl_toolkits.mplot3d import Axes3D
np.random.seed(42)
X1 = np.random.randint(-150, 150, size=(300, 1))
X2 = np.random.randint(0, 300, size=(300, 1))
true_w = np.random.randint(1, 5, size=2)
true_b = np.random.randint(1, 10, size=1)
y = true_w[0] * X1 + true_w[1] * X2 + true_b + np.random.randn(300, 1)
# 创建模型实例
model = LinearRegression()
X = np.concatenate([X1, X2], axis=1)
model.fit(X, y)
y_pred = model.predict(X)
r2 = r2_score(y, y_pred)
print(f"r方:{r2}")
w_ = model.coef_
b_ = model.intercept_
print(f"真实截距:{true_b},预测的截距:{b_}, 真实的斜率:{true_w}, 预测的斜率:{w_}")
# 计算残差
# 这里使用 flatten() 是因为 scatter 的 c 参数通常需要一个一维数组
residuals = np.abs(y.flatten() - y_pred.flatten())
# 设定一个残差阈值。这里使用残差的均值作为阈值,你可以根据需要调整
# 例如:threshold = np.mean(residuals) + np.std(residuals)
threshold = np.mean(residuals) * 1.5
# threshold = np.percentile(residuals, 95)
# 也可以直接设定一个固定值,例如:threshold = 2.0
# --- 核心修改2:根据阈值创建颜色数组 ---
colors = np.where(residuals < threshold, 'darkblue', 'red')
is_normal = residuals < threshold
prop = is_normal.sum() / len(residuals)
print(f"正常的比例:{prop}")
fig = plt.figure(figsize=(10, 8), dpi = 100)
# 创建3D Axes
ax3d = fig.add_subplot(111, projection="3d")
# 绘制三维散点图
scatter_3d = ax3d.scatter(
X1, X2, y,
c=colors, # 颜色值
# cmap='RdYlBu_r', # 颜色映射,_r表示反转,蓝色代表残差小,红色代表残差大
alpha=0.7,
marker="o",
edgecolor="k",
lw=0.5,
depthshade=True,
label="原始数据点"
)
# 回归平面图
w_solved = w_.reshape(-1, 1)
x_grid = np.linspace(-150, 150, 100)
y_grid = np.linspace(0, 300, 100)
x_plot, y_plot = np.meshgrid(x_grid, y_grid)
Z = w_solved[0] * x_plot + w_solved[1] * y_plot + b_
ax3d.plot_surface(x_plot, y_plot, Z, color="lightblue", label="回归平面", alpha = 0.5)
# 设置3D轴标签
ax3d.set_xlabel("X1 特征", fontsize=12, color="red")
ax3d.set_ylabel("X2 特征", fontsize=12, color="green")
ax3d.set_zlabel("值", fontsize=12, color="blue")
# 添加标题和图例
ax3d.set_title("多元线性回归sklearn", fontsize=16)
ax3d.legend()
# 设置初始视角(可选)
ax3d.view_init(elev=20, azim=45)# 仰角和方位角
plt.tight_layout()
plt.show()
4.其他回归和案例:多项式回归
多项式回归(Polynomial Regression)是一种特殊的线性回归形式。尽管它的曲线是弯曲的,但模型本身对于系数是线性的。它的核心思想是:将原始特征通过多项式转换,生成新的特征,然后将这些新特征输入标准的线性回归模型。
例如,对于一个一元二次方程模型:\(y=\theta_0+\theta_1x_+\theta_2x^2\)。我们可以定义一个新的特征 \(x_{new}=x^2\),那么模型就变成了 \(y=\theta_0+\theta_1x_1+\theta_2x_{new}\)。这仍然是一个线性回归模型,因此可以使用前面介绍的任何方法(正规方程、梯度下降、scikit-learn
)来求解。
通过这种特征转换,线性模型能够捕捉数据中的非线性关系。scikit-learn
中的 PolynomialFeatures
类可以自动生成多项式特征。
多项式回归通过特征工程(Feature Engineering),将原始特征 x 转换为一组新的特征:
\[X_1=x, X_2=x^2, ..., X_n=x^n\]然后,我们用这些新生成的特征来训练一个标准的线性回归模型。对于模型本身来说,模型内部的求解机制完全是线性的。
这就是为什么多项式回归可以使用与标准线性回归完全相同的求解算法(正规方程、梯度下降、最小二乘法等)。因为它在本质上就是对转换后的特征进行的线性回归。
4.1多项式回归的优点和缺点
优点:
- 捕捉非线性关系: 能够拟合出比直线更复杂的曲线,更好地拟合非线性数据。
- 实现简单: 只需要在标准线性回归之前添加一个特征转换步骤,不需要改变底层的求解算法。
- 可解释性: 尽管有新的特征,但模型参数 theta 的意义仍然相对清晰。
缺点:
- 过拟合风险: 随着多项式阶数(degree)的增加,模型的复杂度会急剧上升。高阶多项式可能完美地拟合训练数据,但无法泛化到新数据,导致过拟合。
- 特征爆炸: 当原始特征数量较多时,多项式转换会生成大量的交叉项(如 \(x_1x_2,x_1^2x_2,dots\)),导致特征维度急剧增加,增加计算负担和过拟合风险。
4.2学习代码参考
【1】生成非线性的数据:
1
2
3
4
5
6
np.random.seed(42)
m = 100 # 点的个数
X = 6 * np.random.rand(m, 1) - 3 # -3, 3范围
# 添加噪声np.random.randn(m, 1)
y = 0.5 * (X ** 2) + X + 2 + np.random.randn(m, 1)
【2】多形式回归
1
2
3
4
5
6
7
8
9
10
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
# 使用多项式回归
# 串联特征Pipeline
pipeline = Pipeline([
("poly_features", PolynomialFeatures(degree=2, include_bias=False)),
("lin_reg", LinearRegression())
])
pipeline.fit(X, y)
【3】预测:
1
2
3
4
5
6
7
8
9
from sklearn.metrics import r2_score
w_ = pipeline.named_steps["lin_reg"].coef_
b_ = pipeline.named_steps["lin_reg"].intercept_
print(f"真实截距:{2},预测的截距:{b_}, 真实的斜率:{1, 0.5}, 预测的斜率:{w_}")
y_pred = pipeline.predict(X)
r2 = r2_score(y, y_pred)
print(f"R方:{r2}")
【4】画图:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 绘制原始数据
plt.figure(figsize=(8, 6))
plt.scatter(X, y, label='原始非线性数据')
# 3. 绘制回归曲线
X_new = np.linspace(-3, 3, 100).reshape(100, 1)
y_new = pipeline.predict(X_new)
plt.plot(X_new, y_new, 'r-', linewidth=2, label='多项式回归曲线 (degree=2)')
plt.title('多项式回归')
plt.xlabel('特征 X')
plt.ylabel('目标值 y')
plt.legend()
plt.grid(True)
plt.show()
5.岭回归 (Ridge Regression)
岭回归是一种解决过拟合和多重共线性问题的线性回归模型。它的核心思想是在普通最小二乘法(OLS)的成本函数中增加一个L2正则化项(L2 regularization term)。
什么是过拟合? 当模型在训练数据上表现非常好,但在测试数据上表现很差时,就发生了过拟合。这通常是因为模型学习了训练数据中的噪声,导致其泛化能力下降。
什么是多重共线性? 当模型中的两个或多个特征之间存在高度相关性时,就发生了多重共线性。这会导致最小二乘法得到的系数(w
)变得不稳定,方差很大,使得模型对数据微小的变化变得非常敏感。
岭回归的成本函数:将斜率作为误差项引入,使得模型不要对某个因变量的变化过于敏感
其中:
- 第一项是标准的均方误差(MSE),衡量模型的拟合度。
- 第二项是L2正则化项(\(\alpha\)乘上所有模型系数(θ1,θ2,…,θn)的平方和)。\(\alpha\) 是一个超参数,用于控制正则化强度。\(\alpha\)越大,正则化惩罚越强,模型系数会被推向0。
L2正则化的作用: L2正则化通过对所有系数的平方和进行惩罚,使得模型倾向于选择较小的系数。它的作用是:
- 减少过拟合:限制模型参数的大小,从而降低模型的复杂度。
- 处理多重共线性:当特征高度相关时,L2正则化会缩减相关特征的系数,使得它们都变小但都不会变成0,从而使模型更稳定。
归纳总结:
- 岭回归通过添加L2正则化项来约束模型参数。
- 它能解决多重共线性和过拟合问题。
- 它会缩小系数,但不会将系数变为0,因此不会进行特征选择。
- 岭回归的超参数\(\alpha\)需要通过交叉验证等方法进行调优。
为什么截距项\(\theta_0\)不在L2正则中?
截距项 \(θ_0\) 通常不包含在正则化项中。这是因为截距项代表当所有特征都为0时的基准值,它不会影响模型对特征变化的敏感性,因此不需要对其进行惩罚。
代码:比较普通线性回归和岭回归
【1】准备数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
np.random.seed(42)
# 生成有多重共线性的数据
X_base = np.linspace(0, 10, 30).reshape(-1, 1)
X1 = X_base + np.random.randn(30, 1) # 带有少量的噪声
X2 = X_base * 0.9 + np.random.randn(30, 1) * 0.1 # 与X1高度相关
X = np.concatenate([X1, X2], axis=1)
true_w = np.array([2.5, 3.0])
true_b = 5.0
y = X1 * true_w[0] + X2 * true_w[1] + true_b + np.random.randn(30, 1)
【2】普通线性回归
1
2
3
4
5
6
7
# 普通线性回归
from sklearn.linear_model import LinearRegression
model1 = LinearRegression()
model1.fit(X, y)
print(f"回归线的系数:{model1.coef_}, 截距:{model1.intercept_}")
【3】岭回归
1
2
3
4
5
6
# 岭回归
from sklearn.linear_model import Ridge
model2 = Ridge(alpha=1.0)
model2.fit(X, y)
print(f"岭回归线的系数:{model1.coef_}, 截距:{model1.intercept_}")
分别用 LinearRegression
(普通线性回归)和 Ridge
(岭回归)对同一组数据进行了拟合,但得到的结果几乎完全一样
原因在于选择的超参数 alpha 和数据本身的性质。
多重共线性问题在现实数据中通常比这更复杂,导致系数方差非常大,此时岭回归的优势才会凸显出来。
绘制一张图,展示不同 alpha 值下,岭回归系数的变化(观察随着正则化强度的增大,系数是如何被压缩的)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 岭回归 - 尝试一个更大的 alpha 值
# 我把 alpha 增大到 1000.0,你会看到系数明显变小
alpha_value = 1000.0
model2 = Ridge(alpha=alpha_value)
model2.fit(X, y)
print(f"岭回归(alpha={alpha_value})系数: {model2.coef_}, 截距: {model2.intercept_}")
# 如果想画图,可以这样做:
alphas = [0.1, 1, 10, 100, 1000, 10000]
coefs = []
for a in alphas:
ridge = Ridge(alpha=a)
ridge.fit(X, y)
coefs.append(ridge.coef_[0])
plt.figure(figsize=(10, 6))
plt.plot(alphas, coefs, 'o-')
plt.xscale('log') # 使用对数坐标,因为alpha变化范围大
plt.xlabel('alpha')
plt.ylabel('Coefficients')
plt.title('Ridge Coefficients vs. alpha')
plt.legend([f"Coef for X1", f"Coef for X2"])
plt.show()
6.Lasso 回归 (Lasso Regression)
Lasso (Least Absolute Shrinkage and Selection Operator) 回归与岭回归类似,也是一种带有正则化的线性回归方法,但它使用L1正则化项(L1 regularization term)。
Lasso 回归的成本函数:
其中:
- 第一项是标准的均方误差。
- 第二项是L1正则化项,对所有系数的绝对值之和进行惩罚。
L1正则化有一个非常重要的特性:它能将一些不重要的特征的系数直接缩减为0。
- 特征选择:由于L1正则化可以产生稀疏解(即很多系数为0),因此它能够自动进行特征选择,将不重要的特征从模型中剔除。这对于特征数量非常多的情况非常有用。
- 处理过拟合:和岭回归一样,Lasso也能通过约束系数大小来防止过拟合。
归纳总结:
- Lasso 回归通过添加L1正则化项来约束模型参数。
- 它能解决过拟合问题。
- 它能够将不重要的特征的系数变为0,从而实现自动特征选择。
- Lasso 的超参数 \(\alpha\) 同样需要调优
使用方法参考:
1
2
3
from sklearn.linear_model import Lasso
lasso_reg = Lasso(alpha=0.1)
lasso_reg.fit(X, y)
7.普通线性回归、岭回归与Lasso回归比较
普通线性回归 | 岭回归 | Lasso回归 | |
---|---|---|---|
成本函数 | MSE(均方误差)![]() |
MSE + L2 惩罚项![]() |
MSE + L1 惩罚项![]() |
对系数的影响 | 不做任何约束 | 缩小系数,但不为0 | 缩小系数,可能为0 |
特征选择 | 不具备 | 不具备 | 具备(将系数变为0) |
主要应用场景 | 数据特征少,无多重共线性 | 特征间存在多重共线性,或需降低过拟合 | 特征数量多,需进行特征选择 |
8.弹性网络 (Elastic Net)
弹性网络结合了岭回归和Lasso的优点,其成本函数同时包含L1和L2正则化项:
其中 \(\alpha\) 控制整体正则化强度,\(\rho\) 控制L1和L2正则化的混合比例。当\(\rho=1\) 时,它等同于Lasso;当 \(\rho=0\) 时,它等同于岭回归。