逻辑回归概述
逻辑回归是用于解决二分类问题 的经典算法,尽管名称含"回归",实为分类模型。其核心思想是通过线性组合加非线性变换,将输入特征映射到[0,1]区间,表示样本属于正类的概率:
z = w T x + b z = \mathbf{w}^T \mathbf{x} + b z=wTx+b
y ^ = σ ( z ) = 1 1 + e − z \hat{y} = \sigma(z) = \frac{1}{1 + e^{-z}} y^=σ(z)=1+e−z1
其中 σ ( z ) \sigma(z) σ(z)为sigmoid函数,其特性如下:
输入特征 x 线性变换 z = w·x + b Sigmoid激活函数 概率输出 ŷ = σ(z)
sigmoid函数
计算示例
逻辑回归损失函数
损失函数 用域名衡量预测结构与真实值之间的误差。最简单的损失函数定义方式为平方差损失:
L ( y ^ , y ) = 1 2 ( y ^ − y ) 2 L(\hat{y},y)=\frac {1}{2}(\hat{y}-y)^2 L(y^,y)=21(y^−y)2
而逻辑回归 一般使用 : L ( y ^ , y ) = − ( y l o g y ^ ) − ( 1 − y ) l o g ( 1 − y ^ ) L(\hat{y},y)=-(ylog\hat{y})-(1-y)log(1-\hat{y}) L(y^,y)=−(ylogy^)−(1−y)log(1−y^)
该式子的理解:
- 如何 y = 1 y=1 y=1,损失为 − l o g y ^ -log\hat{y} −logy^,那么要想损失越小, h a t y hat{y} haty的值必须越大,即越趋近于或者等于1
- 如果 y = 0 y=0 y=0,损失为 − l o g ( 1 − y ^ ) -log(1-\hat{y}) −log(1−y^),那么要想损失越小,那么 y ^ \hat{y} y^的值越小,即趋近于或者等于0
损失函数是在单个训练样本中定义的,它衡量了在单个训练样本上的表现。代价函数衡量的是在全体训练样本上的表现,即衡量参数 w w w和 b b b的效果,所以训练样本的损失平均值 为:
J ( w , b ) = 1 m Σ i = 1 m L ( y ^ ( i ) , y ( i ) ) J(w,b)=\frac {1}{m}\Sigma_{i=1}^{m}L(\hat{y}^{(i)},y^{(i)}) J(w,b)=m1Σi=1mL(y^(i),y(i))
梯度下降算法
梯度下降图示
可以看到,成本函数 J J J是一个凸函数 ,包含多个局部最低。
通过最小化损失函数来优化参数 w \mathbf{w} w和 b b b:
w : = w − α ∂ J ∂ w \mathbf{w} := \mathbf{w} - \alpha \frac{\partial J}{\partial \mathbf{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的步伐长度。当 w w w大于最优解 w ′ w^{'} w′时,导数大于0,那么 w w w就会向更小的方向更新。反之当 w w w小于最优解 w ′ w^{'} w′时,导数小于0,那么 w w w就会向更大的方向更新。迭代直到收敛。
向量化梯度计算
向量化梯度计算原理
在逻辑回归中,向量化梯度计算的核心思想是使用矩阵运算替代循环操作,大幅提升计算效率。其数学基础是:
给定:
- 特征矩阵 X ∈ R m × n X \in \mathbb{R}^{m \times n} X∈Rm×n(m个样本,n个特征)
- 参数向量 w ∈ R n w \in \mathbb{R}^{n} w∈Rn
- 偏置 b ∈ R b \in \mathbb{R} b∈R
- 预测值 y ^ = σ ( X w + b ) \hat{y} = \sigma(Xw + b) y^=σ(Xw+b)
- 真实标签 y ∈ R m y \in \mathbb{R}^{m} y∈Rm
梯度计算可向量化为:
∇ w J = 1 m X T ( y ^ − y ) \nabla_w J = \frac{1}{m} X^T (\hat{y} - y) ∇wJ=m1XT(y^−y)
∇ b J = 1 m ∑ i = 1 m ( y ^ ( i ) − y ( i ) ) \nabla_b J = \frac{1}{m} \sum_{i=1}^{m} (\hat{y}^{(i)} - y^{(i)}) ∇bJ=m1i=1∑m(y^(i)−y(i))
优势对比:
方法 | 时间复杂度 | 代码简洁性 | 计算效率 |
---|---|---|---|
循环迭代 | O ( m × n ) O(m \times n) O(m×n) | 低 | 低 |
向量化 | O ( 1 ) O(1) O(1) 矩阵运算 | 高 | 高(加速10-100倍) |
伪代码实现
# 输入:特征矩阵X,标签y,参数w,偏置b,样本数m
# 输出:权重梯度dw,偏置梯度db
前向传播:
Z = X · w + b # 矩阵乘法 (m×n)·(n×1) = (m×1)
Y_hat = sigmoid(Z) # 元素级sigmoid函数
计算梯度:
error = Y_hat - y # 预测误差 (m×1)
dw = (1/m) * (Xᵀ · error) # (n×m)·(m×1) = (n×1)
db = (1/m) * sum(error) # 标量
简单示例说明
假设我们有3个样本和2个特征:
输入数据:
X = [[2, 3], # 样本1
[1, 4], # 样本2
[3, 1]] # 样本3
y = [1, 0, 1] # 真实标签
w = [0.5, -0.2] # 初始权重
b = 0.1 # 初始偏置
计算步骤:
-
前向传播(向量化):
Z = X·w + b = [[2*0.5 + 3*(-0.2) + 0.1], [1*0.5 + 4*(-0.2) + 0.1], [3*0.5 + 1*(-0.2) + 0.1]] = [0.5, -0.2, 1.4] Y_hat = sigmoid(Z) ≈ [0.622, 0.450, 0.802]
-
计算误差:
error = Y_hat - y = [0.622-1, 0.450-0, 0.802-1] = [-0.378, 0.450, -0.198]
-
向量化梯度计算:
dw = (1/3) * Xᵀ · error = (1/3) * [[2, 1, 3], # X转置 [3, 4, 1]] · [[-0.378], [ 0.450], [-0.198]] = (1/3) * [[2*(-0.378) + 1*0.450 + 3*(-0.198)], [3*(-0.378) + 4*0.450 + 1*(-0.198)]] = (1/3) * [[-0.756 + 0.450 - 0.594], [-1.134 + 1.800 - 0.198]] = (1/3) * [[-0.900], [0.468]] ≈ [[-0.300], [0.156]] db = (1/3) * sum(error) = (1/3) * (-0.378 + 0.450 - 0.198) = (1/3) * (-0.126) = -0.042
Python实现对比
循环实现(低效)
python
def compute_gradients_loop(X, y, w, b):
m, n = X.shape
dw = np.zeros(n)
db = 0
for i in range(m):
z_i = np.dot(X[i], w) + b
a_i = 1 / (1 + np.exp(-z_i))
dz_i = a_i - y[i]
for j in range(n):
dw[j] += X[i, j] * dz_i
db += dz_i
dw /= m
db /= m
return dw, db
向量化实现(高效)
python
def compute_gradients_vectorized(X, y, w, b):
m = X.shape[0]
Z = np.dot(X, w) + b
A = 1 / (1 + np.exp(-Z))
dZ = A - y
dw = (1/m) * np.dot(X.T, dZ)
db = (1/m) * np.sum(dZ)
return dw, db
性能对比测试
python
import time
import numpy as np
# 生成大数据集 (10,000样本, 100特征)
X_large = np.random.randn(10000, 100)
y_large = np.random.randint(0, 2, 10000)
w_large = np.random.randn(100)
b_large = 0
# 测试循环实现
start = time.time()
dw_loop, db_loop = compute_gradients_loop(X_large, y_large, w_large, b_large)
loop_time = time.time() - start
# 测试向量化实现
start = time.time()
dw_vec, db_vec = compute_gradients_vectorized(X_large, y_large, w_large, b_large)
vec_time = time.time() - start
print(f"循环实现时间: {loop_time:.4f}秒")
print(f"向量化实现时间: {vec_time:.4f}秒")
print(f"加速比: {loop_time/vec_time:.1f}x")
print(f"梯度差异: {np.linalg.norm(dw_loop - dw_vec):.6f}")
典型输出:
输出示例
向量化背后的数学原理
-
矩阵微分规则 :
∂ ∂ w ( X w ) = X T \frac{\partial}{\partial w}(Xw) = X^T ∂w∂(Xw)=XT -
链式法则的向量形式 :
∇ w J = ∂ J ∂ y ^ ⋅ ∂ y ^ ∂ z ⋅ ∂ z ∂ w \nabla_w J = \frac{\partial J}{\partial \hat{y}} \cdot \frac{\partial \hat{y}}{\partial z} \cdot \frac{\partial z}{\partial w} ∇wJ=∂y^∂J⋅∂z∂y^⋅∂w∂z其中:
- ∂ J ∂ y ^ = y ^ − y y ^ ( 1 − y ^ ) \frac{\partial J}{\partial \hat{y}} = \frac{\hat{y} - y}{\hat{y}(1-\hat{y})} ∂y^∂J=y^(1−y^)y^−y
- ∂ y ^ ∂ z = y ^ ( 1 − y ^ ) \frac{\partial \hat{y}}{\partial z} = \hat{y}(1-\hat{y}) ∂z∂y^=y^(1−y^)
- ∂ z ∂ w = X T \frac{\partial z}{\partial w} = X^T ∂w∂z=XT
简化后:
∇ w J = X T ( y ^ − y ) \nabla_w J = X^T (\hat{y} - y) ∇wJ=XT(y^−y) -
广播机制:
python# 标量b自动广播到向量运算中 Z = X.dot(w) + b # b被加到每个样本上
Python实现逻辑回归
完整代码
python
import numpy as np
import matplotlib.pyplot as plt
class LogisticRegression:
def __init__(self, learning_rate=0.01, n_iters=1000):
self.lr = learning_rate
self.n_iters = n_iters
self.weights = None
self.bias = None
def _sigmoid(self, z):
return 1 / (1 + np.exp(-z))
def fit(self, X, y):
n_samples, n_features = X.shape
self.weights = np.zeros(n_features)
self.bias = 0
# 梯度下降优化
for _ in range(self.n_iters):
# 前向传播
linear_model = np.dot(X, self.weights) + self.bias
y_pred = self._sigmoid(linear_model)
# 反向传播(向量化计算梯度)
dw = (1 / n_samples) * np.dot(X.T, (y_pred - y))
db = (1 / n_samples) * np.sum(y_pred - y)
# 参数更新
self.weights -= self.lr * dw
self.bias -= self.lr * db
def predict_prob(self, X):
linear_model = np.dot(X, self.weights) + self.bias
return self._sigmoid(linear_model)
def predict(self, X, threshold=0.5):
return (self.predict_prob(X) >= threshold).astype(int)
# 测试示例
if __name__ == "__main__":
# 生成示例数据
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=100, n_features=2, n_redundant=0,
n_informative=2, random_state=42)
# 训练模型
model = LogisticRegression(learning_rate=0.1, n_iters=1000)
model.fit(X, y)
predictions = model.predict(X)
# 计算准确率
accuracy = np.mean(predictions == y)
print(f"Model accuracy: {accuracy:.4f}")
# 可视化决策边界
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired, edgecolors='k')
ax = plt.gca()
xlim = ax.get_xlim()
ylim = ax.get_ylim()
# 创建网格以绘制决策边界
xx, yy = np.meshgrid(np.linspace(xlim[0], xlim[1], 50),
np.linspace(ylim[0], ylim[1], 50))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.Paired)
plt.title("Logistic Regression Decision Boundary")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.show()
- 输出示例
完整代码输出示例
代码结构详解
1. 导入必要的库
python
import numpy as np
import matplotlib.pyplot as plt
- numpy:用于高效的数值计算和矩阵运算
- matplotlib.pyplot:用于数据可视化,绘制决策边界
2. LogisticRegression类定义
2.1 初始化方法 __init__
python
def __init__(self, learning_rate=0.01, n_iters=1000):
self.lr = learning_rate
self.n_iters = n_iters
self.weights = None
self.bias = None
- learning_rate:学习率,控制梯度下降的步长
- n_iters:梯度下降的迭代次数
- weights:特征权重向量(待训练)
- bias:偏置项(待训练)
2.2 Sigmoid激活函数 _sigmoid
python
def _sigmoid(self, z):
return 1 / (1 + np.exp(-z))
- 将线性输出转换为概率值(0-1之间)
- 公式: σ ( z ) = 1 1 + e − z \sigma(z) = \frac{1}{1 + e^{-z}} σ(z)=1+e−z1
- 函数曲线特性:
- 当 z → ∞ z \to \infty z→∞ 时, σ ( z ) → 1 \sigma(z) \to 1 σ(z)→1
- 当 z → − ∞ z \to -\infty z→−∞ 时, σ ( z ) → 0 \sigma(z) \to 0 σ(z)→0
- 当 z = 0 z = 0 z=0 时, σ ( z ) = 0.5 \sigma(z) = 0.5 σ(z)=0.5
2.3 训练方法 fit
python
def fit(self, X, y):
n_samples, n_features = X.shape
self.weights = np.zeros(n_features)
self.bias = 0
- 输入 :
X
:训练数据特征矩阵(形状:n_samples × n_features)y
:训练数据标签向量(形状:n_samples)
- 初始化:权重初始化为零向量,偏置初始化为0
python
# 梯度下降优化
for _ in range(self.n_iters):
# 前向传播
linear_model = np.dot(X, self.weights) + self.bias
y_pred = self._sigmoid(linear_model)
- 前向传播 :
- 计算线性部分: z = X ⋅ w + b z = X \cdot w + b z=X⋅w+b
- 应用sigmoid激活: y ^ = σ ( z ) \hat{y} = \sigma(z) y^=σ(z)
python
# 反向传播(向量化计算梯度)
dw = (1 / n_samples) * np.dot(X.T, (y_pred - y))
db = (1 / n_samples) * np.sum(y_pred - y)
- 梯度计算 (向量化实现):
- 权重梯度: ∂ J ∂ w = 1 m X T ( y ^ − y ) \frac{\partial J}{\partial w} = \frac{1}{m} X^T (\hat{y} - y) ∂w∂J=m1XT(y^−y)
- 偏置梯度: ∂ J ∂ b = 1 m ∑ ( y ^ − y ) \frac{\partial J}{\partial b} = \frac{1}{m} \sum (\hat{y} - y) ∂b∂J=m1∑(y^−y)
python
# 参数更新
self.weights -= self.lr * dw
self.bias -= self.lr * db
- 参数更新 :使用梯度下降算法
- 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 预测方法
python
def predict_prob(self, X):
linear_model = np.dot(X, self.weights) + self.bias
return self._sigmoid(linear_model)
- 返回样本属于正类的概率(0-1之间)
python
def predict(self, X, threshold=0.5):
return (self.predict_prob(X) >= threshold).astype(int)
- 根据阈值(默认0.5)将概率转换为类别预测
- 概率 ≥ threshold 预测为正类(1),否则为负类(0)
3. 测试与可视化
3.1 生成示例数据
python
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=100, n_features=2, n_redundant=0,
n_informative=2, random_state=42)
- 使用scikit-learn生成二分类数据集
- 100个样本,2个特征,无冗余特征
- random_state=42确保结果可复现
3.2 模型训练与评估
python
model = LogisticRegression(learning_rate=0.1, n_iters=1000)
model.fit(X, y)
predictions = model.predict(X)
accuracy = np.mean(predictions == y)
print(f"Model accuracy: {accuracy:.4f}")
- 创建模型实例(学习率0.1,迭代1000次)
- 训练模型
- 在训练集上预测并计算准确率
3.3 决策边界可视化
python
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired, edgecolors='k')
- 创建散点图,不同颜色表示不同类别
python
ax = plt.gca()
xlim = ax.get_xlim()
ylim = ax.get_ylim()
# 创建网格点
xx, yy = np.meshgrid(np.linspace(xlim[0], xlim[1], 50),
np.linspace(ylim[0], ylim[1], 50))
- 获取当前坐标轴范围
- 创建覆盖整个绘图区域的网格点
python
# 预测网格点的类别
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# 绘制决策边界
plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.Paired)
- 将网格点转换为特征矩阵进行预测
- 使用等高线填充绘制决策区域
python
plt.title("Logistic Regression Decision Boundary")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.show()
- 添加标题和轴标签
- 显示可视化结果
关键概念图解
1. 逻辑回归工作流程
输入特征 线性变换 z = w·x + b Sigmoid激活 ŷ = σ(z) 概率输出 0-1 二元分类决策
2. 梯度下降优化过程
否 是 初始化参数 前向传播计算预测值 计算损失函数 反向传播计算梯度 更新参数 达到最大迭代次数? 输出最终模型
总结
逻辑回归作为深度学习的基础组件,具有以下特点:
- 通过sigmoid函数实现概率输出
- 使用交叉熵损失函数优化分类性能
- 依赖梯度下降进行参数更新
- 向量化实现显著提升计算效率