当前位置: 首页 > news >正文

从零构建逻辑回归: sklearn 与自定义实现对比

文章目录


尽管名字中有“回归”二字,逻辑回归(Logistic Regression)实际上是一种分类方法,主要用于二分类问题。它通过一个线性模型与 Sigmoid 函数的结合,将问题转化为一个概率预测问题,并基于该概率来做分类决策。下面将详细讲解逻辑回归的工作原理、损失函数、梯度推导、以及如何通过梯度下降来优化模型。


理论基础

1. 逻辑回归模型

逻辑回归的核心是 Sigmoid 函数,也称为 逻辑函数。它可以将任何实数值映射到区间 [0, 1] 内,因此非常适合用于概率预测。Sigmoid 函数的形式为:

σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+ez1

其中 (z) 是线性回归的输出,可以表示为:

z = w T x + b z = w^T x + b z=wTx+b

这里:

  • w w w 是权重向量(模型参数之一),
  • x x x 是输入特征向量,
  • b b b 是偏置项。

因此,Sigmoid 函数的输出 y ^ = σ ( z ) \hat{y} = \sigma(z) y^=σ(z) 表示样本属于正类(即 y = 1 y = 1 y=1)的概率。对于二分类问题,模型的目标是预测输入样本属于类别1的概率:

P ( y = 1 ∣ x ) = σ ( w T x + b ) P(y = 1 | x) = \sigma(w^T x + b) P(y=1∣x)=σ(wTx+b)

如果 y ^ ≥ 0.5 \hat{y} \geq 0.5 y^0.5,则预测样本为正类 y = 1 y = 1 y=1,否则预测为负类 y = 0 y = 0 y=0


2. 损失函数

逻辑回归使用 交叉熵损失函数(Cross-Entropy Loss)来衡量模型的预测与真实标签之间的差异。交叉熵损失函数的形式如下:

L ( y , y ^ ) = − [ y log ⁡ ( y ^ ) + ( 1 − y ) log ⁡ ( 1 − y ^ ) ] L(y, \hat{y}) = - \left[ y \log(\hat{y}) + (1 - y) \log(1 - \hat{y}) \right] L(y,y^)=[ylog(y^)+(1y)log(1y^)]

其中:

  • y y y 是真实标签(0 或 1),
  • y ^ \hat{y} y^ 是模型预测的概率。

对于整个训练集,损失函数 J ( w , b ) J(w, b) J(w,b) 是所有样本损失的平均值,具体形式为:

J ( w , b ) = − 1 m ∑ i = 1 m [ y ( i ) log ⁡ ( y ^ ( i ) ) + ( 1 − y ( i ) ) log ⁡ ( 1 − y ^ ( i ) ) ] J(w, b) = -\frac{1}{m} \sum_{i=1}^m \left[ y^{(i)} \log(\hat{y}^{(i)}) + (1 - y^{(i)}) \log(1 - \hat{y}^{(i)}) \right] J(w,b)=m1i=1m[y(i)log(y^(i))+(1y(i))log(1y^(i))]

其中 m m m 是训练集中的样本数量。


3. 梯度推导

为了优化逻辑回归模型,我们需要通过梯度下降算法最小化损失函数。首先,我们需要计算损失函数相对于模型参数 w w w b b b 的梯度。

(1) 计算 ∂ L ∂ y ^ \frac{\partial L}{\partial \hat{y}} y^L

损失函数对预测值的导数为:

∂ L ∂ y ^ = − ( y y ^ − 1 − y 1 − y ^ ) \frac{\partial L}{\partial \hat{y}} = -\left( \frac{y}{\hat{y}} - \frac{1 - y}{1 - \hat{y}} \right) y^L=(y^y1y^1y)

(2) 计算 ∂ y ^ ∂ z \frac{\partial \hat{y}}{\partial z} zy^

Sigmoid 函数的导数为:

∂ y ^ ∂ z = y ^ ( 1 − y ^ ) \frac{\partial \hat{y}}{\partial z} = \hat{y} (1 - \hat{y}) zy^=y^(1y^)

(3) 计算 ∂ L ∂ z \frac{\partial L}{\partial z} zL

根据链式法则,可以得到:

∂ L ∂ z = ∂ L ∂ y ^ ⋅ ∂ y ^ ∂ z = y ^ − y \frac{\partial L}{\partial z} = \frac{\partial L}{\partial \hat{y}} \cdot \frac{\partial \hat{y}}{\partial z} = \hat{y} - y zL=y^Lzy^=y^y

(4) 计算 ∂ z ∂ w \frac{\partial z}{\partial w} wz ∂ z ∂ b \frac{\partial z}{\partial b} bz

线性回归的输出对权重和偏置的导数为:

∂ z ∂ w = x , ∂ z ∂ b = 1 \frac{\partial z}{\partial w} = x, \quad \frac{\partial z}{\partial b} = 1 wz=x,bz=1

(5) 计算 ∂ L ∂ w \frac{\partial L}{\partial w} wL ∂ L ∂ b \frac{\partial L}{\partial b} bL

根据链式法则:

∂ L ∂ w = ( y ^ − y ) ⋅ x \frac{\partial L}{\partial w} = (\hat{y} - y) \cdot x wL=(y^y)x

∂ L ∂ b = y ^ − y \frac{\partial L}{\partial b} = \hat{y} - y bL=y^y

对于整个训练集,梯度是所有样本梯度的平均值:

∂ J ∂ w = 1 m ∑ i = 1 m ( y ^ ( i ) − y ( i ) ) ⋅ x ( i ) \frac{\partial J}{\partial w} = \frac{1}{m} \sum_{i=1}^m (\hat{y}^{(i)} - y^{(i)}) \cdot x^{(i)} wJ=m1i=1m(y^(i)y(i))x(i)

∂ J ∂ b = 1 m ∑ i = 1 m ( y ^ ( i ) − y ( i ) ) \frac{\partial J}{\partial b} = \frac{1}{m} \sum_{i=1}^m (\hat{y}^{(i)} - y^{(i)}) bJ=m1i=1m(y^(i)y(i))


4. 梯度下降

梯度下降是一种优化算法,用于最小化损失函数并学习最佳的模型参数。梯度下降的更新规则如下:

w : = w − α ∂ J ∂ w w := w - \alpha \frac{\partial J}{\partial w} w:=wαwJ

b : = b − α ∂ J ∂ b b := b - \alpha \frac{\partial J}{\partial b} b:=bαbJ

其中, α \alpha α 是学习率,控制每次更新的步长。

梯度下降的执行步骤:
  1. 初始化参数 w w w b b b
  2. 计算损失函数 J ( w , b ) J(w, b) J(w,b)
  3. 计算梯度 ∂ J ∂ w \frac{\partial J}{\partial w} wJ ∂ J ∂ b \frac{\partial J}{\partial b} bJ
  4. 更新参数:
    w : = w − α ∂ J ∂ w w := w - \alpha \frac{\partial J}{\partial w} w:=wαwJ
    b : = b − α ∂ J ∂ b b := b - \alpha \frac{\partial J}{\partial b} b:=bαbJ
  5. 重复步骤 2-4,直到损失函数收敛或达到最大迭代次数。

5. 总结

逻辑回归通过将线性回归的结果通过 Sigmoid 函数转化为概率,并使用交叉熵损失函数来衡量模型的误差。通过反向传播计算梯度,并利用梯度下降优化参数,逻辑回归模型可以逐步学习到最优的分类边界,适用于二分类问题。


项目结构

project_root/
├── my_sklearn/
│   ├── linear_model/
│   │   ├── __init__.py
│   │   └── logistic_regression.py
│   ├── metrics/
│   │   ├── __init__.py
│   │   └── accuracy.py
│   └── __init__.py
└── main.py

代码实现

1. my_sklearn/linear_model/logistic_regression.py — 自定义逻辑回归实现
# my_sklearn/linear_model/logistic_regression.py
# 包含逻辑回归模型的实现import numpy as npclass MyLogisticRegression:def __init__(self, learning_rate=0.01, epochs=1000):self.learning_rate = learning_rate  # 学习率self.epochs = epochs  # 迭代次数self.weights = None  # 权重self.bias = None  # 偏置# Sigmoid 激活函数def sigmoid(self, linear_output):result = 1 / (1 + np.exp(-linear_output))return result# 损失函数:交叉熵损失def compute_loss(self, X, y):m = len(y)predictions = self.sigmoid(np.dot(X, self.weights) + self.bias)loss = -1/m * np.sum(y * np.log(predictions) + (1 - y) * np.log(1 - predictions))return loss# 训练模型def fit(self, X, y):m, n = X.shapeself.weights = np.zeros(n)self.bias = 0for epoch in range(self.epochs):# 前向传播z = np.dot(X, self.weights) + self.bias  # 计算线性组合predictions = self.sigmoid(z)  # 通过sigmoid函数得到概率# 反向传播dw = (1/m) * np.dot(X.T, (predictions - y))db = (1/m) * np.sum(predictions - y)# 更新参数self.weights -= self.learning_rate * dwself.bias -= self.learning_rate * db# 每100次迭代输出一次损失if epoch % 100 == 0:loss = self.compute_loss(X, y)print(f"Epoch {epoch}: Loss = {loss}")# 预测def predict(self, X):z = np.dot(X, self.weights) + self.biaspredictions = self.sigmoid(z)class_predictions = np.where(predictions >= 0.5, 1, 0)return class_predictions

2. my_sklearn/metrics/accuracy.py — 自定义准确率计算
# my_sklearn/metrics/accuracy.pydef my_accuracy_score(y_true, y_pred):"""计算准确率:正确预测的样本数 / 总样本数参数:y_true -- 真实标签y_pred -- 预测标签返回:accuracy -- 准确率"""correct = sum(y_true == y_pred)total = len(y_true)accuracy = correct / totalreturn accuracy

3. my_sklearn/linear_model/__init__.py — 导出 MyLogisticRegression
# my_sklearn/linear_model/__init__.py
# linear_model子包初始化文件# 从logistic_regression模块导入类
from .logistic_regression import MyLogisticRegression# 导出的类列表
__all__ = ['MyLogisticRegression'] 

4. my_sklearn/metrics/__init__.py — 导出准确率函数
# my_sklearn/metrics/__init__.py
# metrics子包初始化文件# 从accuracy模块导入函数
from .accuracy import my_accuracy_score# 导出的函数列表
__all__ = ['my_accuracy_score'] 

5. my_sklearn/__init__.py — 主包初始化
# my_sklearn/__init__.py
# 主包初始化文件# 导入子模块,使它们可以通过my_sklearn.xxx直接访问
from . import metrics
from . import linear_model 

6. main.py — 主程序文件,包含数据处理和模型对比
# main.pyimport numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression as SklearnLogisticRegression
from sklearn.metrics import accuracy_score  # 导入sklearn的准确率计算函数# 导入自定义模块
from my_sklearn.linear_model import MyLogisticRegression  # 导入自定义逻辑回归模型
from my_sklearn.metrics import my_accuracy_score  # 导入自定义准确率计算函数# 1. 加载鸢尾花数据集
iris = datasets.load_iris()
X = iris.data
y = iris.target# 只选择两类进行二分类
X = X[y != 2]
y = y[y != 2]# 2. 数据预处理(标准化)
scaler = StandardScaler()
X = scaler.fit_transform(X)# 3. 切分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)# 4. 使用自定义实现的逻辑回归
my_lr = MyLogisticRegression(learning_rate=0.01, epochs=1000)
my_lr.fit(X_train, y_train)# 5. 使用 sklearn 实现的逻辑回归
sklearn_lr = SklearnLogisticRegression(max_iter=1000)
sklearn_lr.fit(X_train, y_train)# 6. 对比自定义模型和 sklearn 模型的预测准确度
my_pred = my_lr.predict(X_test)
sklearn_pred = sklearn_lr.predict(X_test)# 使用自定义函数计算自定义模型的准确率
my_accuracy = my_accuracy_score(y_test, my_pred)
# 使用sklearn的函数计算sklearn模型的准确率
sklearn_accuracy = accuracy_score(y_test, sklearn_pred)print(f"My Logistic Regression Accuracy: {my_accuracy * 100:.2f}%")
print(f"Sklearn Logistic Regression Accuracy: {sklearn_accuracy * 100:.2f}%")

项目使用说明

  1. 安装依赖
    由于此项目只使用了 numpysklearn 库,你可以通过以下命令安装它们:

    pip install numpy scikit-learn
    
  2. 运行项目
    运行 main.py 文件来加载数据集、训练模型并对比自定义模型和 sklearn 版本的准确度:

    python main.py
    

总结

这个项目实现了自定义的逻辑回归模型,并与 sklearn 的实现进行了对比。结构上,模仿了 sklearn 的模块化方式,将功能分为 linear_modelmetrics 两个子模块。


http://www.mrgr.cn/news/93875.html

相关文章:

  • [数据结构]并查集--C++版本的实现代码
  • sparkTTS window 安装
  • 数据集构建与训练前准备
  • OpenHarmony5.0分布式系统源码实现分析—软总线
  • C++蓝桥杯皮亚诺曲线距离求解
  • Cline使用MCP-TypeScript版本
  • MCP-代码解读TypeScript版本
  • 尚硅谷TS快速入门笔记(个人笔记用)
  • 通义万相2.1技术深度解析
  • 【面试】框架
  • 6-langchang多模态输入和自定义输出
  • 【Java学习】泛型
  • 【面试】MySQL
  • 力扣刷题(数组篇)
  • Dify 本地部署问题:install 界面一直转圈
  • 计算机网络----主要内容简介
  • Dify 本地部署教程
  • 《今日AI-人工智能-编程日报》
  • 对开源VLA sota π0的微调——如何基于各种开源数据集、以及你自己的私有数据集微调π0(含我司的微调实践)
  • 群晖DS 223 Docker:开启私有云