前言
提醒:
文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。
其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展及意见建议,欢迎评论区讨论交流。
分类与回归算法
机器学习中的分类与回归算法是两种主要的监督学习任务,它们分别用于解决不同类型的问题。以下是这两种算法的总结:
分类算法:
分类算法用于将数据分成不同的类别,适用于输出为离散标签的问题。常见的分类算法包括:
- 逻辑回归:使用逻辑函数来估计概率,用于二分类问题,也可以扩展到多分类问题。
- 支持向量机(SVM):通过找到最优的决策边界来最大化样本的分类准确率,适用于高维数据。
- 决策树:通过树结构来进行决策,每个节点代表一个特征的选择,叶子节点代表分类结果。
- 随机森林:由多个决策树组成的集成学习方法,通过投票来决定最终分类结果。
- 梯度提升决策树(GBDT):通过构建和结合多个弱学习器来形成强学习器,适用于分类和回归问题。
- 朴素贝叶斯:基于贝叶斯定理,假设特征之间相互独立,适用于文本分类等场景。
- K近邻(KNN):根据样本之间的距离进行分类,适用于小规模数据集。
- 神经网络:通过多层感知机学习数据的复杂模式,适用于图像、语音等复杂分类问题。
回归算法:
回归算法用于预测连续数值输出,适用于输出为连续变量的问题。常见的回归算法包括:
- 线性回归:通过拟合一条直线来预测目标变量的值,是最简单的回归方法。
- 岭回归:线性回归的扩展,通过引入L2正则化项来防止过拟合。
- Lasso回归:线性回归的另一种扩展,通过引入L1正则化项来进行特征选择。
- 弹性网回归:结合了岭回归和Lasso回归,同时引入L1和L2正则化项。
- 决策树回归:使用决策树结构来进行回归预测,适用于非线性关系。
- 随机森林回归:由多个决策树组成的集成学习方法,通过平均来决定最终回归结果。
- 梯度提升决策树回归(GBDT回归):通过构建和结合多个弱学习器来形成强学习器,适用于回归问题。
- 支持向量回归(SVR):支持向量机在回归问题上的应用,通过找到最优的决策边界来最大化样本的回归准确率。
- 神经网络回归:通过多层感知机学习数据的复杂模式,适用于复杂的回归问题。
分类与回归算法的比较:
- 输出类型:分类算法输出离散标签,回归算法输出连续数值。
- 评估指标:分类算法常用准确率、召回率、F1分数等指标,回归算法常用均方误差(MSE)、均方根误差(RMSE)等指标。
- 问题类型:分类算法适用于类别预测问题,如垃圾邮件检测;回归算法适用于数值预测问题,如房价预测。 在实际应用中,选择分类还是回归算法取决于问题的性质和需求。有时,可以将回归问题转化为分类问题,或者将分类问题转化为回归问题,具体取决于问题的特点和目标。
弹性网回归
弹性网回归(Elastic Net Regression)是一种用于线性回归的正则化算法,它结合了L1和L2正则化的特点,以下结合数学公式对其进行讲解:
线性回归基础
假设我们有一组数据集
{
(
x
i
,
y
i
)
}
i
=
1
n
\{(x_{i}, y_{i})\}_{i = 1}^{n}
{(xi,yi)}i=1n,其中
x
i
=
(
x
i
1
,
x
i
2
,
⋯
,
x
i
p
)
x_{i}=(x_{i1},x_{i2},\cdots,x_{ip})
xi=(xi1,xi2,⋯,xip) 是
p
p
p 维特征向量,
y
i
y_{i}
yi 是对应的目标值。线性回归模型的目标是找到一个线性函数
y
=
β
0
+
β
1
x
1
+
⋯
+
β
p
x
p
y = \beta_{0}+\beta_{1}x_{1}+\cdots+\beta_{p}x_{p}
y=β0+β1x1+⋯+βpxp,使得预测值
y
^
i
\hat{y}_{i}
y^i 与真实值
y
i
y_{i}
yi 之间的误差最小。
通常使用最小二乘法来估计模型的参数
β
=
(
β
0
,
β
1
,
⋯
,
β
p
)
\beta = (\beta_{0},\beta_{1},\cdots,\beta_{p})
β=(β0,β1,⋯,βp),损失函数为:
J
(
β
)
=
∑
i
=
1
n
(
y
i
−
y
^
i
)
2
=
∑
i
=
1
n
(
y
i
−
∑
j
=
0
p
β
j
x
i
j
)
2
J(\beta)=\sum_{i = 1}^{n}(y_{i}-\hat{y}_{i})^{2}=\sum_{i = 1}^{n}(y_{i}-\sum_{j = 0}^{p}\beta_{j}x_{ij})^{2}
J(β)=i=1∑n(yi−y^i)2=i=1∑n(yi−j=0∑pβjxij)2
1. 弹性网回归的损失函数
相关参考:
python回归算法_线性回归
python回归算法_岭回归(L2正则化)
python回归算法_Lasso回归(L1正则化)
弹性网回归的损失函数由三部分组成:残差平方和(RSS)、L1正则化项和L2正则化项。具体形式如下:
L
(
w
)
=
1
2
n
∑
i
=
1
n
(
y
i
−
w
0
−
∑
j
=
1
p
w
j
x
i
j
)
2
+
α
(
ρ
∑
j
=
1
p
∣
w
j
∣
+
1
−
ρ
2
∑
j
=
1
p
w
j
2
)
\mathcal{L}(w) = \frac{1}{2n} \sum_{i=1}^{n}(y_i - w_0 - \sum_{j=1}^{p}w_j x_{ij})^2 + \alpha \left( \rho \sum_{j=1}^{p}|w_j| + \frac{1-\rho}{2} \sum_{j=1}^{p}w_j^2 \right)
L(w)=2n1i=1∑n(yi−w0−j=1∑pwjxij)2+α(ρj=1∑p∣wj∣+21−ρj=1∑pwj2)
其中:
- n n n 是样本数量, p p p 是特征数量。
- y i y_i yi 是第 i i i 个样本的因变量, x i j x_{ij} xij 是第 i i i 个样本的第 j j j 个特征。
- w 0 w_0 w0 是截距项, w j w_j wj 是第 j j j 个特征的回归系数。
- α \alpha α 是正则化强度参数,控制正则化项的影响力。
- ρ \rho ρ 是L1和L2正则化之间的权衡参数,取值范围为 [ 0 , 1 ] [0, 1] [0,1]。当 ρ = 1 \rho = 1 ρ=1 时,弹性网回归退化为Lasso回归;当 ρ = 0 \rho = 0 ρ=0 时,退化为岭回归。
2. 弹性网回归的求解过程
弹性网回归的求解通常采用坐标下降法(Coordinate Descent)算法,这是一种迭代优化算法,通过逐个优化变量来最小化损失函数。具体步骤如下:
- 初始化参数:设置初始的回归系数 w w w 和截距 w 0 w_0 w0,以及正则化参数 α \alpha α 和 ρ \rho ρ。
- 迭代优化:
- 对于每个特征 j j j,固定其他特征的回归系数,只优化 w j w_j wj。
- 计算损失函数关于
w
j
w_j
wj 的梯度,并使用软阈值操作更新
w
j
w_j
wj:
w j : = S ( α ρ , α ( 1 − ρ ) ) ( w j − 1 L j ( ∂ L ( w ) ∂ w j + α ( ρ ⋅ sign ( w j ) + ( 1 − ρ ) ⋅ w j ) ) ) w_j := \mathcal{S}_{(\alpha \rho, \alpha(1-\rho))} \left( w_j - \frac{1}{L_j} \left( \frac{\partial \mathcal{L}(w)}{\partial w_j} + \alpha \left( \rho \cdot \text{sign}(w_j) + (1-\rho) \cdot w_j \right) \right) \right) wj:=S(αρ,α(1−ρ))(wj−Lj1(∂wj∂L(w)+α(ρ⋅sign(wj)+(1−ρ)⋅wj)))
其中, L j L_j Lj 是损失函数关于 w j w_j wj 的二阶导数(Hessian矩阵对角线上的元素), S ( ⋅ ) \mathcal{S}_{(\cdot)} S(⋅) 是一个软阈值函数,用来实现L1正则项的特征选择能力。
- 收敛判断:当所有回归系数的更新量小于某个阈值,或者达到预设的最大迭代次数时,算法停止迭代。
3. 弹性网回归的优势
- 处理共线性:通过L2正则化项,弹性网回归可以有效地处理特征间的高度共线性问题,使得模型的系数更加稳定。
- 特征选择:L1正则化项提供了变量选择的功能,有助于构建稀疏模型,提高模型的可解释性。
- 灵活性:通过调整 ρ \rho ρ 的值,可以在岭回归和Lasso回归之间进行权衡,根据实际问题的需求选择合适的模型。
4. 参数选择
- 正则化强度 α \alpha α:控制模型复杂度和过拟合之间的平衡。较大的 α \alpha α 值意味着更强的正则化,可能导致更多的特征权重为0(L1部分)或接近0(L2部分)。
- 权衡参数 ρ \rho ρ:控制L1和L2正则项的相对强度。当 ρ \rho ρ 接近1时,模型倾向于更稀疏的解,即更多的特征权重为0;当 ρ \rho ρ 接近0时,模型趋向于保留所有特征,但将其权重压缩到一起。
通过合理选择 α \alpha α 和 ρ \rho ρ,弹性网回归能够在处理高维数据和多重共线性问题时表现出色,同时具备特征选择和模型稳定性的优点。
算法实现
手动实现
import numpy as np
import matplotlib.pyplot as plt
class ElasticNetRegression:
def __init__(self, alpha=1.0, l1_ratio=0.5, max_iter=1000, tol=1e-4):
# 正则化强度
self.alpha = alpha
# L1 正则化比例
self.l1_ratio = l1_ratio
# 最大迭代次数
self.max_iter = max_iter
# 收敛阈值
self.tol = tol
# 模型系数
self.coef_ = None
# 截距
self.intercept_ = None
def fit(self, X, y):
# 添加偏置项
X = np.c_[np.ones((X.shape[0], 1)), X]
n_samples, n_features = X.shape
# 初始化系数
beta = np.zeros(n_features)
for _ in range(self.max_iter):
beta_old = beta.copy()
for j in range(n_features):
# 计算残差
r = y - X @ beta + X[:, j] * beta[j]
# 计算更新值
z = X[:, j].T @ X[:, j]
rho = X[:, j].T @ r
if j == 0:
# 截距项不进行正则化
beta[j] = rho / z
else:
if self.l1_ratio == 1:
# Lasso 回归
if rho < -self.alpha:
beta[j] = (rho + self.alpha) / z
elif rho > self.alpha:
beta[j] = (rho - self.alpha) / z
else:
beta[j] = 0
else:
# 弹性网回归
shrinkage = self.alpha * self.l1_ratio
penalty = self.alpha * (1 - self.l1_ratio)
if rho < -shrinkage:
beta[j] = (rho + shrinkage) / (z + penalty)
elif rho > shrinkage:
beta[j] = (rho - shrinkage) / (z + penalty)
else:
beta[j] = 0
# 检查收敛
if np.linalg.norm(beta - beta_old) < self.tol:
break
self.intercept_ = beta[0]
self.coef_ = beta[1:]
return self
def predict(self, X):
return X @ self.coef_ + self.intercept_
# 生成一维示例数据
np.random.seed(42)
n_samples = 100
X = np.sort(np.random.rand(n_samples)).reshape(-1, 1)
# 生成具有一定噪声的目标值
y = 2 * X.flatten() + 1 + 0.5 * np.random.randn(n_samples)
# 创建弹性网回归模型
model = ElasticNetRegression(alpha=0.1, l1_ratio=0.5, max_iter=1000, tol=1e-4)
# 拟合模型
model.fit(X, y)
# 进行预测
x_range = np.linspace(X.min(), X.max(), 100).reshape(-1, 1)
y_pred = model.predict(x_range)
# 可视化
plt.figure(figsize=(10, 6))
# 绘制原始数据点
plt.scatter(X, y, color='blue', label='Original Data')
# 绘制预测曲线
plt.plot(x_range, y_pred, color='red', label='Prediction Curve')
plt.xlabel('X')
plt.ylabel('y')
plt.title('Elastic Net Regression: Original Data vs Prediction Curve')
plt.legend()
plt.grid(True)
plt.show()
# 输出结果
print("Coefficients:", model.coef_)
print("Intercept:", model.intercept_)
运行结果:
python函数库实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import ElasticNet
from sklearn.model_selection import train_test_split
# 生成一维示例数据
np.random.seed(42)
n_samples = 100
# 生成在 [0, 1] 区间内的随机数,并排序,然后转换为二维数组
X = np.sort(np.random.rand(n_samples)).reshape(-1, 1)
# 根据线性关系生成目标值,并添加高斯噪声
y = 2 * X.flatten() + 1 + 0.5 * np.random.randn(n_samples)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建弹性网回归模型
# alpha 是正则化强度,l1_ratio 是 L1 正则化的比例
model = ElasticNet(alpha=0.1, l1_ratio=0.5)
# 拟合模型
model.fit(X_train, y_train)
# 进行预测
x_range = np.linspace(X.min(), X.max(), 100).reshape(-1, 1)
y_pred = model.predict(x_range)
# 可视化
plt.figure(figsize=(10, 6))
# 绘制训练数据点
plt.scatter(X_train, y_train, color='blue', label='Training Data')
# 绘制测试数据点
plt.scatter(X_test, y_test, color='green', label='Testing Data')
# 绘制预测曲线
plt.plot(x_range, y_pred, color='red', label='Prediction Curve')
plt.xlabel('X')
plt.ylabel('y')
plt.title('Elastic Net Regression: Original Data vs Prediction Curve')
plt.legend()
plt.grid(True)
plt.show()
# 输出结果
print("Coefficients:", model.coef_)
print("Intercept:", model.intercept_)
运行结果: