文章目录
- 理论基础
- 1. 逻辑回归模型
- 2. 损失函数
- 3. 梯度推导
- (1) 计算 ∂ L ∂ y ^ \frac{\partial L}{\partial \hat{y}} ∂y^∂L
- (2) 计算 ∂ y ^ ∂ z \frac{\partial \hat{y}}{\partial z} ∂z∂y^
- (3) 计算 ∂ L ∂ z \frac{\partial L}{\partial z} ∂z∂L
- (4) 计算 ∂ z ∂ w \frac{\partial z}{\partial w} ∂w∂z 和 ∂ z ∂ b \frac{\partial z}{\partial b} ∂b∂z
- (5) 计算 ∂ L ∂ w \frac{\partial L}{\partial w} ∂w∂L 和 ∂ L ∂ b \frac{\partial L}{\partial b} ∂b∂L
- 4. 梯度下降
- 梯度下降的执行步骤:
- 5. 总结
- 项目结构
- 代码实现
- 1. `my_sklearn/linear_model/logistic_regression.py` — 自定义逻辑回归实现
- 2. `my_sklearn/metrics/accuracy.py` — 自定义准确率计算
- 3. `my_sklearn/linear_model/__init__.py` — 导出 `MyLogisticRegression`
- 4. `my_sklearn/metrics/__init__.py` — 导出准确率函数
- 5. `my_sklearn/__init__.py` — 主包初始化
- 6. `main.py` — 主程序文件,包含数据处理和模型对比
- 项目使用说明
- 总结
尽管名字中有“回归”二字,逻辑回归(Logistic Regression)实际上是一种分类方法,主要用于二分类问题。它通过一个线性模型与 Sigmoid 函数的结合,将问题转化为一个概率预测问题,并基于该概率来做分类决策。下面将详细讲解逻辑回归的工作原理、损失函数、梯度推导、以及如何通过梯度下降来优化模型。
这篇文章也写的不错:
Python实现逻辑回归(Logistic Regression)
理论基础
1. 逻辑回归模型
逻辑回归的核心是 Sigmoid 函数,也称为 逻辑函数。它可以将任何实数值映射到区间 [0, 1] 内,因此非常适合用于概率预测。Sigmoid 函数的形式为:
σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+e−z1
其中 (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^)+(1−y)log(1−y^)]
其中:
- 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=1∑m[y(i)log(y^(i))+(1−y(i))log(1−y^(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^y−1−y^1−y)
(2) 计算 ∂ y ^ ∂ z \frac{\partial \hat{y}}{\partial z} ∂z∂y^
Sigmoid 函数的导数为:
∂ y ^ ∂ z = y ^ ( 1 − y ^ ) \frac{\partial \hat{y}}{\partial z} = \hat{y} (1 - \hat{y}) ∂z∂y^=y^(1−y^)
(3) 计算 ∂ L ∂ z \frac{\partial L}{\partial z} ∂z∂L
根据链式法则,可以得到:
∂ 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 ∂z∂L=∂y^∂L⋅∂z∂y^=y^−y
(4) 计算 ∂ z ∂ w \frac{\partial z}{\partial w} ∂w∂z 和 ∂ z ∂ b \frac{\partial z}{\partial b} ∂b∂z
线性回归的输出对权重和偏置的导数为:
∂ z ∂ w = x , ∂ z ∂ b = 1 \frac{\partial z}{\partial w} = x, \quad \frac{\partial z}{\partial b} = 1 ∂w∂z=x,∂b∂z=1
(5) 计算 ∂ L ∂ w \frac{\partial L}{\partial w} ∂w∂L 和 ∂ L ∂ b \frac{\partial L}{\partial b} ∂b∂L
根据链式法则:
∂ L ∂ w = ( y ^ − y ) ⋅ x \frac{\partial L}{\partial w} = (\hat{y} - y) \cdot x ∂w∂L=(y^−y)⋅x
∂ L ∂ b = y ^ − y \frac{\partial L}{\partial b} = \hat{y} - y ∂b∂L=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)} ∂w∂J=m1i=1∑m(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)}) ∂b∂J=m1i=1∑m(y^(i)−y(i))
4. 梯度下降
梯度下降是一种优化算法,用于最小化损失函数并学习最佳的模型参数。梯度下降的更新规则如下:
w : = w − α ∂ J ∂ w w := w - \alpha \frac{\partial J}{\partial w} w:=w−α∂w∂J
b : = b − α ∂ J ∂ b b := b - \alpha \frac{\partial J}{\partial b} b:=b−α∂b∂J
其中, α \alpha α 是学习率,控制每次更新的步长。
梯度下降的执行步骤:
- 初始化参数 w w w 和 b b b。
- 计算损失函数 J ( w , b ) J(w, b) J(w,b)。
- 计算梯度 ∂ J ∂ w \frac{\partial J}{\partial w} ∂w∂J 和 ∂ J ∂ b \frac{\partial J}{\partial b} ∂b∂J。
- 更新参数:
w : = w − α ∂ J ∂ w w := w - \alpha \frac{\partial J}{\partial w} w:=w−α∂w∂J
b : = b − α ∂ J ∂ b b := b - \alpha \frac{\partial J}{\partial b} b:=b−α∂b∂J - 重复步骤 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 np
class 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.shape
self.weights = np.zeros(n)
self.bias = 0
for 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 * dw
self.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.bias
predictions = 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.py
def my_accuracy_score(y_true, y_pred):
"""
计算准确率:正确预测的样本数 / 总样本数
参数:
y_true -- 真实标签
y_pred -- 预测标签
返回:
accuracy -- 准确率
"""
correct = sum(y_true == y_pred)
total = len(y_true)
accuracy = correct / total
return 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.py
import 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}%")
项目使用说明
-
安装依赖:
由于此项目只使用了numpy
和sklearn
库,你可以通过以下命令安装它们:pip install numpy scikit-learn
-
运行项目:
运行main.py
文件来加载数据集、训练模型并对比自定义模型和 sklearn 版本的准确度:python main.py
总结
这个项目实现了自定义的逻辑回归模型,并与 sklearn 的实现进行了对比。结构上,模仿了 sklearn 的模块化方式,将功能分为 linear_model
和 metrics
两个子模块。