1. 决策边界:逻辑回归的分类本质
逻辑回归虽然名字里有"回归",但它实际上是一种经典的分类算法。它的核心思想是通过一个S形函数(Sigmoid函数)将线性回归的输出映射到0到1之间,作为样本属于某一类的概率估计。
Sigmoid函数的数学表达式为:
python复制σ(z) = 1 / (1 + e^(-z))
其中z是线性组合:z = w₁x₁ + w₂x₂ + ... + wₙxₙ + b
决策边界就是在这个概率空间中,将预测为类别1和类别0的区域分开的界线。具体来说,当σ(z) ≥ 0.5时,我们预测类别1;当σ(z) < 0.5时,预测类别0。由于σ(z)=0.5对应z=0,所以决策边界实际上就是z=0这个超平面。
注意:虽然Sigmoid函数输出值在0-1之间,但它并不是概率密度函数。逻辑回归输出的"概率"更应该理解为一种置信度评分。
在二维特征空间中,决策边界是一条直线(对于线性逻辑回归);在高维空间中,它是一个超平面。如果我们使用多项式特征,决策边界可以变成曲线或更复杂的形状,这为处理非线性可分数据提供了可能。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 成本函数:逻辑回归的学习目标
2.1 原始成本函数推导
逻辑回归不能直接使用线性回归的均方误差(MSE)作为成本函数,因为Sigmoid函数会导致MSE成为非凸函数,存在多个局部最小值,不利于优化。
我们需要的成本函数应该满足:
- 当预测值接近真实标签时,成本接近0
- 当预测值远离真实标签时,成本迅速增大
- 整体函数是凸的,便于梯度下降找到全局最小值
基于这些要求,逻辑回归的成本函数通常定义为:
code复制J(w,b) = -1/m * Σ [yⁱ log(ŷⁱ) + (1-yⁱ) log(1-ŷⁱ)]
其中:
- m是样本数量
- yⁱ是第i个样本的真实标签(0或1)
- ŷⁱ是模型对第i个样本的预测值(σ(zⁱ))
这个函数也称为交叉熵损失函数。它的直观理解是:对于正样本(y=1),-log(ŷ)在ŷ接近1时趋近0,在ŷ接近0时趋近+∞;对于负样本(y=0),-log(1-ŷ)有类似的性质。
2.2 简化后的成本函数
将上述分段函数合并,可以得到更简洁的表达:
code复制J(w,b) = -1/m * Σ [yⁱ log(σ(zⁱ)) + (1-yⁱ) log(1-σ(zⁱ))]
这个形式在实现时更加方便。我们可以进一步将其向量化:
python复制def compute_cost(X, y, w, b):
m = X.shape[0]
z = np.dot(X, w) + b
ŷ = 1/(1+np.exp(-z))
cost = -np.mean(y*np.log(ŷ) + (1-y)*np.log(1-ŷ))
return cost
实际编程时需要注意数值稳定性问题。当z很大时,e^(-z)可能下溢为0;当z很负时,e^(-z)可能上溢。可以通过对σ(z)的计算进行数值优化来避免这些问题。
3. 梯度下降实现
3.1 梯度推导
为了使用梯度下降优化成本函数,我们需要计算其对w和b的偏导数。经过推导可得:
∂J/∂w_j = 1/m * Σ (ŷⁱ - yⁱ)x_jⁱ
∂J/∂b = 1/m * Σ (ŷⁱ - yⁱ)
这看起来与线性回归的梯度形式相似,但要注意ŷⁱ在这里是通过Sigmoid函数计算得到的。
3.2 实现步骤
完整的梯度下降算法实现如下:
- 初始化参数w和b(通常设为0或小随机数)
- 计算当前预测值ŷ = σ(Xw + b)
- 计算梯度:
- dw = (1/m) * Xᵀ(ŷ - y)
- db = (1/m) * sum(ŷ - y)
- 更新参数:
- w = w - α * dw
- b = b - α * db
- 重复步骤2-4直到收敛
Python实现示例:
python复制def gradient_descent(X, y, w, b, alpha, num_iters):
m = X.shape[0]
costs = []
for i in range(num_iters):
z = np.dot(X, w) + b
ŷ = 1/(1+np.exp(-z))
dw = (1/m) * np.dot(X.T, (ŷ - y))
db = (1/m) * np.sum(ŷ - y)
w = w - alpha * dw
b = b - alpha * db
cost = compute_cost(X, y, w, b)
costs.append(cost)
return w, b, costs
3.3 学习率选择
学习率α的选择至关重要:
- 太大:可能无法收敛,甚至发散
- 太小:收敛速度过慢
建议的做法是尝试一系列值(如0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1),观察成本函数下降曲线。好的学习率应该使成本函数平稳、较快地下降。
4. 过拟合问题及其解决方案
4.1 识别过拟合
过拟合是指模型在训练集上表现很好,但在测试集上表现较差的现象。在逻辑回归中,过拟合通常表现为:
- 训练准确率很高而测试准确率明显较低
- 决策边界过于复杂,完美分隔所有训练样本(包括可能的噪声点)
- 模型参数(权重)的绝对值很大
4.2 解决过拟合的方法
- 获取更多训练数据:这是最有效但往往最难实现的方法
- 特征选择:使用更少的特征,减少模型复杂度
- 正则化:在成本函数中加入对大型权重的惩罚项
4.3 正则化的实现
4.3.1 L2正则化
最常用的是L2正则化(也称为权重衰减),修改后的成本函数为:
code复制J(w,b) = -1/m * Σ [yⁱ log(ŷⁱ) + (1-yⁱ) log(1-ŷⁱ)] + λ/(2m) * Σ w_j²
其中λ是正则化参数,控制正则化的强度。
对应的梯度也需要调整:
code复制∂J/∂w_j = [1/m * Σ (ŷⁱ - yⁱ)x_jⁱ] + (λ/m)w_j
∂J/∂b = 1/m * Σ (ŷⁱ - yⁱ) # b通常不正则化
4.3.2 正则化参数λ的选择
λ的选择需要权衡:
- λ太大:模型过于简单,可能欠拟合
- λ太小:正则化效果不明显,可能过拟合
通常通过交叉验证来选择最优的λ值。常见做法是在对数尺度上尝试一系列值(如0.01, 0.1, 1, 10, 100)。
4.3.3 实现示例
带L2正则化的梯度下降实现:
python复制def compute_cost_reg(X, y, w, b, lambda_):
m = X.shape[0]
cost = compute_cost(X, y, w, b)
reg_cost = (lambda_/(2*m)) * np.sum(w**2)
return cost + reg_cost
def gradient_descent_reg(X, y, w, b, alpha, num_iters, lambda_):
m = X.shape[0]
costs = []
for i in range(num_iters):
z = np.dot(X, w) + b
ŷ = 1/(1+np.exp(-z))
dw = (1/m) * np.dot(X.T, (ŷ - y)) + (lambda_/m)*w
db = (1/m) * np.sum(ŷ - y)
w = w - alpha * dw
b = b - alpha * db
cost = compute_cost_reg(X, y, w, b, lambda_)
costs.append(cost)
return w, b, costs
5. 逻辑回归的实践技巧
5.1 特征缩放
虽然逻辑回归不像某些算法(如SVM)那样严格要求特征缩放,但进行适当的特征标准化通常能:
- 加速梯度下降的收敛
- 帮助正则化更公平地对待所有特征
常用的特征缩放方法包括:
- 标准化:(x - μ)/σ
- 最大最小缩放:(x - min)/(max - min)
5.2 多分类问题
逻辑回归本质上是二分类器,但可以通过以下策略扩展到多分类:
- 一对多(One-vs-Rest):为每个类别训练一个二分类器,判断"属于该类"vs"不属于该类"
- 多项式逻辑回归(Softmax回归):直接推广逻辑回归到多类情况
5.3 评估指标
准确率并不总是最佳评估指标,特别是在类别不平衡时。其他有用指标包括:
- 精确率(Precision):预测为正的样本中实际为正的比例
- 召回率(Recall):实际为正的样本中被正确预测的比例
- F1分数:精确率和召回率的调和平均
- ROC曲线和AUC:综合考察不同阈值下的表现
5.4 与线性回归的对比
虽然逻辑回归和线性回归都使用线性组合,但关键区别在于:
- 输出:线性回归输出连续值,逻辑回归输出概率
- 成本函数:线性回归用MSE,逻辑回归用交叉熵
- 优化目标:线性回归最小化预测值与真实值的距离,逻辑回归最大化数据似然
在实际项目中,我经常发现初学者会混淆这两种算法。一个简单的记忆方法是:如果目标变量是连续的,考虑线性回归;如果是分类问题(特别是二分类),逻辑回归通常是更好的起点。
