逻辑回归原理、梯度下降推导及代码实现

逻辑回归基本原理

逻辑回归(Logistic Regression)是一种广泛应用于二分类问题(也可扩展到多分类)的线性模型。它通过Sigmoid函数将线性组合的输入特征映射到概率值:P(y=1|x) = Sigmoid(w\ast x) = \frac{1}{1 + e^{-w \ast x}}

逻辑回归如何处理多分类问题

LR也可以用于多分类任务,其基本思想是:将多分类任务拆分成若干个二分类任务,然后对每个二分类任务训练一个模型,最后将多个模型的结果进行集成以获得最终的分类结果。一般来说,可以采取的拆分策略有:

  • one vs one策略:假设我们有N个类别,该策略基本思想就是不同类别两两之间训练一个分类器,这时我们一共会训练出C^2_N种不同的分类器。在预测时,我们将样本提交给所有的分类器,一共会获得N(N-1)/2个结果,最终结果通过投票产生

  • one vs all策略:该策略基本思想就是将第i种类型的所有样本作为正例,将剩下的所有样本作为负例,进行训练得到一个分类器。这样我们就一共可以得到N个分类器。在预测时,我们将样本提交给所有的分类器,一共会获得N个结果,我们选择其中概率值最大的那个作为最终分类结果

  • softmax回归:softmax回归是LR在多分类的推广。若待分类的类别互斥,我们就使用softmax回归;若待分类的类别有相交,我们则要选用多分类LR,然后投票表决

梯度下降求解逻辑回归

逻辑回归的损失为交叉熵损失(负对数似然函数):l = -\sum_i y_i log \hat{y_i} + (1 - y_i) log(1 - \hat{y_i})

我们可以使用梯度下降的方法迭代求解损失函数的最小值,根据求导链式法则,可推导得到逻辑回归参数的梯度(利用sigmoid函数求导的性质:{\sigma}' = \sigma * (1 - \sigma)):

\frac{\partial l}{\partial w} = - \sum_i y_i \frac{1}{\hat{y_i}} \hat{y_i}(1 - \hat{y_i})x - (1-y_i) \frac{1}{1 - \hat{y_i}} \hat{y_i}(1 - \hat{y_i})x

\frac{\partial l}{\partial w} = - \sum_i (y_i - \hat{y_i})x

我们就可以利用梯度下降算法,用负梯度更新模型参数,进行参数求解:

w_{new} = w_{old} - \frac{\partial l}{\partial w} = w_{old} + learning\_rate * \sum_i (y_i - \hat{y_i})x

为啥使用交叉熵损失而不是mse

  • 概率输出的匹配:交叉熵损失直接衡量了预测概率分布与真实标签分布之间的差异,适用于概率输出的模型(如通过softmax或sigmoid函数生成的概率)

  • 梯度优化的有效性

    • 交叉熵损失在概率接近真实标签时,能够提供更强的梯度信号,帮助模型更快地收敛

    • 均方误差(MSE)在分类问题中,尤其是当使用softmax激活函数时,不如交叉熵损失提供的梯度信息有效,可能导致训练速度较慢和收敛效果较差

  • 多类别分类的优势:在多类别分类问题中,交叉熵损失能够自然地扩展到多个类别

逻辑回归numpy代码实现

以下是使用numpy手动实现逻辑回归模型,并利用梯度下降进行训练的代码,且附带L1/L2正则化功能,缓解过拟合风险

import numpy as np
from sklearn.metrics import accuracy_score

# 定义sigmoid函数
def sigmoid(z):
    return 1 / (1 + np.exp(-z))

def compute_loss(y, y_hat, weights, lambda1, lambda2):
    m = y.shape[0]
    # 交叉熵损失
    loss = - (1/m) * np.sum(y * np.log(y_hat) + (1 - y) * np.log(1 - y_hat))
    # L1 正则化
    reg1 = lambda1 * np.sum(np.abs(weights))
    # L2 正则化
    reg2 = lambda2 / (2 * m) * np.sum(weights ** 2)
    return loss + reg1 + reg2

# 定义梯度下降优化算法
def lr_train(X, y, X_test, y_test, learning_rate=0.01, num_iterations=1000, lambda1=0.01, lambda2=0.01):
    m, n = X.shape
    # 初始化权重、偏置为0
    weights = np.zeros(n)
    bias = 0
    losses = []

    for i in range(num_iterations):
        # 计算模型的预测值
        y_hat = sigmoid(np.dot(X, weights) + bias)

        # 计算损失
        loss = compute_loss(y, y_hat, weights, lambda1, lambda2)
        loss_test = compute_loss(y_test, sigmoid(np.dot(X_test, weights) + bias), weights, lambda1, lambda2)
        losses.append(loss)

        # 计算梯度
        dw = -1/m * np.dot(X.T, y - y_hat) + lambda1 * np.sign(weights) + (lambda2 / m) * weights
        db = -1/m * np.sum(y - y_hat) + lambda1 * np.sign(bias) + (lambda2 / m) * bias

        # 更新参数
        weights -= learning_rate * dw
        bias -= learning_rate * db

        # 打印损失值
        if i % 100 == 0:
            print(f"Iteration {i}: Train_loss = {loss}, Test_loss = {loss_test}")

    return weights, bias, losses

# 预测函数
def predict(X, weights, bias):
    z = np.dot(X, weights) + bias
    y_hat = sigmoid(z)
    return (y_hat > 0.5).astype(int)

if __name__ == "__main__":
    # 生成一些示例数据
    X = np.random.randn(1000, 2)
    y = (np.dot(X, np.array([2, -3])) + 1 > 0).astype(int)
    X_train, X_test = X[:800], X[800:]
    y_train, y_test = y[:800], y[800:]

    # 训练逻辑回归模型
    learning_rate = 0.1
    num_iterations = 500
    weights, bias, losses = lr_train(X_train, y_train, X_test, y_test, learning_rate, num_iterations)

    # 打印训练结果
    print(f"Weights: {weights}")
    print(f"Bias: {bias}")

    # 测试模型
    y_pred = predict(X_test, weights, bias)
    print('预测准确率:', accuracy_score(y_test, y_pred))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值