4. 逻辑回归算法原理以及代码实现

相关的实验代码在我的github上👉QYHcrossover/ML-numpy: 机器学习算法numpy实现 (github.com) 欢迎star⭐

逻辑回归原理

逻辑回归(Logistic Regression)是一种用于分类问题的统计学习方法,它将输入特征与输出标签之间的关系建模为一个概率模型。它常被用于二元分类问题(如判断一封邮件是否为垃圾邮件),但也可以扩展到多元分类问题(如手写数字识别)。

在逻辑回归中,我们假设输出变量 y y y(也称为目标变量)是由输入变量 x x x(也称为特征)和一组参数 θ \theta θ 决定的,其中 θ \theta θ 是我们需要学习的模型参数。我们的目标是根据训练数据集中的 x x x y y y,找到一组最佳参数 θ \theta θ,使得我们的模型能够准确地预测未知的输入样本的输出标签 y y y

逻辑回归使用的激活函数是sigmoid函数,它将输入 z z z 映射到一个值 0 ≤ h θ ( x ) ≤ 1 0 \leq h_{\theta}(x) \leq 1 0hθ(x)1,其中 h θ ( x ) h_{\theta}(x) hθ(x) 是我们模型的预测输出,定义为:

h θ ( x ) = 1 1 + e − θ T x h_{\theta}(x) = \frac{1}{1 + e^{-\theta^Tx}} hθ(x)=1+eθTx1

我们可以将这个输出理解为样本 x x x 属于正例( y = 1 y=1 y=1)的概率。在训练过程中,我们需要最小化损失函数 J ( θ ) J(\theta) J(θ),它是由交叉熵计算得出的,定义为:

J ( θ ) = − 1 m ∑ i = 1 m y ( i ) log ⁡ h θ ( x ( i ) ) + ( 1 − y ( i ) ) log ⁡ ( 1 − h θ ( x ( i ) ) ) J(\theta) = -\frac{1}{m} \sum_{i=1}^{m} y^{(i)} \log h_{\theta}(x^{(i)}) + (1-y^{(i)}) \log (1 - h_{\theta}(x^{(i)})) J(θ)=m1i=1my(i)loghθ(x(i))+(1y(i))log(1hθ(x(i)))

其中 m m m 是训练集中的样本数。在这个损失函数中,我们希望训练出的模型能够最小化错误分类的样本数,并且对于误分类的样本,它能够更加严格地惩罚。

在训练过程中,我们使用梯度下降算法来最小化损失函数。具体来说,我们首先随机初始化模型的参数 θ \theta θ,然后在每一步迭代中,计算损失函数的梯度,并按照梯度的方向更新参数 θ \theta θ,直到损失函数收敛或达到了最大迭代次数。

逻辑回归是一种简单但非常强大的分类算法,具有许多应用。由于其计算效率高、易于实现和解释,逻辑回归在实际工作中被广泛使用。

逻辑回归代码实现

import numpy as np

class LogisticRegression:
    def __init__(self,lr=0.001,thr=1e-2,max_epoch=600): #学习率和阈值
        self.lr = lr
        self.thr = thr
        self.max_epoch = max_epoch
        self.best_loss = np.inf
        self.best_theta = None
        self.losses_process = []

首先导入了numpy库,并定义了一个名为LogisticRegression的类。

  • __init__方法初始化了类的实例化对象,接受三个可选参数:学习率(lr)、阈值(thr)和最大迭代次数(max_epoch)。
  • 这三个参数分别代表着学习率、梯度下降的阈值和最大的迭代次数。
  • best_loss、best_theta和losses_process分别代表着最优的损失值、最优的参数和迭代过程中损失值的历史记录。
    def _predict(self,X,theta):
        sigmoid = lambda x: 1/(1+np.exp(-x)) if x>=0 else np.exp(x)/(1+np.exp(x))
        pX = np.ones([X.shape[0],X.shape[1]+1])
        pX[:,:-1] = X
        preds = [sigmoid(i) for i in pX@theta.ravel()]
        return np.array(preds).reshape(-1,1)

_predict方法用于预测数据的标签。

  • sigmoid函数为逻辑函数,将输出压缩在0和1之间。
  • pX矩阵为在原始特征矩阵X前增加一列全1矩阵。
  • theta.ravel()将theta矩阵降维,用于矩阵相乘。
  • 最后返回预测值的矩阵。
    def predict(self,X):
        preds = self._predict(X,self.best_theta).ravel()
        preds[preds<=0.5] = 0
        preds[preds>0.5] = 1
        return preds

predict方法为调用_predict方法的简单包装器,用于预测标签。将预测值矩阵降维并将概率小于等于0.5的预测为0,大于0.5的预测为1,最后返回预测结果。

    def score(self,X,y):
        return np.sum(self.predict(X)==y) / len(y)

score方法为评估模型预测效果的方法。该方法返回预测正确的样本数除以样本总数。

fit函数是逻辑回归算法中的核心部分,它用于训练模型参数。下面我们来逐行解释fit函数中的代码含义。

def fit(self,X,y):
    y = y.reshape(-1,1) # 调整y的维度
    pX = np.ones([X.shape[0],X.shape[1]+1]) # 创建矩阵pX,并将其初始化为1
    pX[:,:-1] = X # 将X的值赋给pX的前n列,n为X的列数

上述代码中,我们首先将y的维度调整为(n,1),其中n为y的长度,然后创建矩阵pX,并将其初始化为1。矩阵pX的行数为X的行数,列数为X的列数+1。这里要将X的值赋给pX的前n列,n为X的列数,是因为我们需要在X中添加一列常数1,用于表示截距项。

	#构造theta
    theta = np.random.randn(X.shape[-1]+1).reshape(-1,1) # 创建theta,并将其初始化为随机值
    #开始训练
    epoch = 0 # 记录训练轮数
    while True:
        #计算loss
        loss = -1/X.shape[0]*np.squeeze(y.T@np.log(self._predict(X,theta)+1e-6) + (1-y).T@np.log(1-self._predict(X,theta)+1e-6)) # 计算交叉熵损失函数
        self.losses_process.append(loss) # 记录损失函数值
        if loss<self.best_loss: # 如果当前的损失函数值小于历史最佳值,则更新最佳值和对应的参数
            self.best_loss = loss
            self.best_theta = theta
#             print("第{}epoch,loss为{}".format(epoch,loss))
        #计算梯度
        grad = pX.T@(self._predict(X,theta)-y) # 计算梯度
        #是否收敛
        if np.sum(np.abs(grad)) < self.thr or epoch>self.max_epoch: break # 判断是否收敛
        #梯度下降
        theta -= self.lr * grad # 更新参数
        epoch += 1 # 更新训练轮数

接下来,我们构造参数theta,并将其初始化为随机值。然后使用while循环进行训练,直到损失函数收敛或达到最大迭代次数。在每一轮训练中,我们首先计算损失函数值,并将其记录在self.losses_process中,然后判断当前的损失函数值是否小于历史最佳值,如果是,则更新历史最佳值和对应的参数。接着,我们计算梯度并判断是否收敛。如果梯度的绝对值之和小于阈值self.thr,则认为模型已经完全收敛了。

最后介绍主函数的主要流程,首先,我们从sklearn.datasets库中加载了乳腺癌数据集,将数据集分别赋值给X和y。然后,我们对X进行标准化处理,接着使用train_test_split函数随机划分数据集为训练集和测试集。

接下来,我们创建了一个逻辑回归对象lr,并将最大迭代次数max_epoch设置为1000。然后,我们使用训练集对逻辑回归模型进行训练,训练完成后我们输出训练集和测试集的分类准确率。最后,我们使用matplotlib库画出了损失函数值随着迭代次数的变化曲线。

if __name__ == "__main__":
    from sklearn.datasets import load_breast_cancer
    from sklearn.model_selection  import train_test_split
    import matplotlib.pyplot as plt

    breast_cancer = load_breast_cancer()
    X = breast_cancer.data
    y = breast_cancer.target
    #数据标准化
    X_std = (X-X.mean(axis=0)) / X.std(axis=0)
    #划分为训练集和测试集
    X_train,X_test,y_train,y_test = train_test_split(X,y)

    #逻辑回归训练
    lr = LogisticRegression(max_epoch=1000)
    lr.fit(X_train,y_train)
    print(f"train score {lr.score(X_train,y_train):.2f}")
    print(f"test  score {lr.score(X_test, y_test):.2f}")

    plt.plot(lr.losses_process)

总结

主要介绍了逻辑回归算法的原理和如何用Python的numpy库实现逻辑回归。其中,主要涵盖了逻辑回归算法的原理、sigmoid函数的作用、损失函数和梯度下降算法的应用。代码中的LogisticRegression类实现了逻辑回归的训练和预测,并用fit函数来训练模型。最后在本地运行代码并测试模型的准确率。

如果想要深入学习机器学习和numpy,可以关注作者的GitHub账号👉https://github.com/QYHcrossover/ML-numpy。在作者的仓库中,有许多关于机器学习和numpy的实现代码和实例,相信对读者的学习会有很大的帮助。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值