python回归算法_弹性网回归

前言

提醒:
文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。
其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展及意见建议,欢迎评论区讨论交流。


分类与回归算法

机器学习中的分类与回归算法是两种主要的监督学习任务,它们分别用于解决不同类型的问题。以下是这两种算法的总结:

  1. 分类算法
    分类算法用于将数据分成不同的类别,适用于输出为离散标签的问题。常见的分类算法包括:

    1. 逻辑回归:使用逻辑函数来估计概率,用于二分类问题,也可以扩展到多分类问题。
    2. 支持向量机(SVM):通过找到最优的决策边界来最大化样本的分类准确率,适用于高维数据。
    3. 决策树:通过树结构来进行决策,每个节点代表一个特征的选择,叶子节点代表分类结果。
    4. 随机森林:由多个决策树组成的集成学习方法,通过投票来决定最终分类结果。
    5. 梯度提升决策树(GBDT):通过构建和结合多个弱学习器来形成强学习器,适用于分类和回归问题。
    6. 朴素贝叶斯:基于贝叶斯定理,假设特征之间相互独立,适用于文本分类等场景。
    7. K近邻(KNN):根据样本之间的距离进行分类,适用于小规模数据集。
    8. 神经网络:通过多层感知机学习数据的复杂模式,适用于图像、语音等复杂分类问题。
  2. 回归算法
    回归算法用于预测连续数值输出,适用于输出为连续变量的问题。常见的回归算法包括:

    1. 线性回归:通过拟合一条直线来预测目标变量的值,是最简单的回归方法。
    2. 岭回归:线性回归的扩展,通过引入L2正则化项来防止过拟合。
    3. Lasso回归:线性回归的另一种扩展,通过引入L1正则化项来进行特征选择。
    4. 弹性网回归:结合了岭回归和Lasso回归,同时引入L1和L2正则化项。
    5. 决策树回归:使用决策树结构来进行回归预测,适用于非线性关系。
    6. 随机森林回归:由多个决策树组成的集成学习方法,通过平均来决定最终回归结果。
    7. 梯度提升决策树回归(GBDT回归):通过构建和结合多个弱学习器来形成强学习器,适用于回归问题。
    8. 支持向量回归(SVR):支持向量机在回归问题上的应用,通过找到最优的决策边界来最大化样本的回归准确率。
    9. 神经网络回归:通过多层感知机学习数据的复杂模式,适用于复杂的回归问题。
  3. 分类与回归算法的比较

    • 输出类型:分类算法输出离散标签,回归算法输出连续数值。
    • 评估指标:分类算法常用准确率、召回率、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=1n(yiy^i)2=i=1n(yij=0pβ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=1n(yiw0j=1pwjxij)2+α(ρj=1pwj+21ρj=1pwj2)
其中:

  • 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)算法,这是一种迭代优化算法,通过逐个优化变量来最小化损失函数。具体步骤如下:

  1. 初始化参数:设置初始的回归系数 w w w 和截距 w 0 w_0 w0,以及正则化参数 α \alpha α ρ \rho ρ
  2. 迭代优化
    • 对于每个特征 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ρ))(wjLj1(wjL(w)+α(ρsign(wj)+(1ρ)wj)))
      其中, L j L_j Lj 是损失函数关于 w j w_j wj 的二阶导数(Hessian矩阵对角线上的元素), S ( ⋅ ) \mathcal{S}_{(\cdot)} S() 是一个软阈值函数,用来实现L1正则项的特征选择能力。
  3. 收敛判断:当所有回归系数的更新量小于某个阈值,或者达到预设的最大迭代次数时,算法停止迭代。

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_)

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值