逻辑回归实战:基于鸢尾花数据集的Sklearn与自定义梯度下降对比实验

1次阅读
没有评论

共计 3300 个字符,预计需要花费 9 分钟才能阅读完成。

image.webp

背景与痛点

逻辑回归是机器学习中最基础的分类算法之一,它通过 sigmoid 函数将线性回归的输出映射到 (0,1) 区间,从而解决二分类问题。虽然原理简单,但初学者常常面临一个困惑:是直接使用 Sklearn 等库提供的现成实现,还是自己动手编写梯度下降等优化算法?

逻辑回归实战:基于鸢尾花数据集的 Sklearn 与自定义梯度下降对比实验

前者虽然方便,但容易成为 ” 黑箱 ”,不利于深入理解算法本质;后者虽然能加深理解,但实现过程中又会遇到各种细节问题。本文将通过鸢尾花数据集的二分类任务,对比这两种实现方式,帮助读者做出更明智的选择。

数据预处理

首先我们需要对原始数据进行处理,只保留前两个特征和类别 0、1 的数据:

from sklearn.datasets import load_iris
import numpy as np

# 加载数据
iris = load_iris()
X = iris.data[:, :2]  # 只取前两个特征
Y = iris.target

# 只保留类别 0 和 1
mask = (Y == 0) | (Y == 1)
X = X[mask]
Y = Y[mask]

# 数据标准化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

Sklearn 实现

Sklearn 的 LogisticRegression 类提供了高度优化的逻辑回归实现,使用起来非常简单:

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, Y, test_size=0.2, random_state=42)

# 创建并训练模型
sk_model = LogisticRegression()
sk_model.fit(X_train, y_train)

# 评估模型
sk_score = sk_model.score(X_test, y_test)
print(f"Sklearn 模型准确率: {sk_score:.4f}")

Sklearn 实现的主要优势在于:

  • 自动处理了很多底层细节(如学习率调整、迭代终止条件等)
  • 提供了丰富的参数调优选项
  • 计算效率高,适合大型数据集

自定义梯度下降实现

为了深入理解逻辑回归的工作原理,我们手动实现梯度下降算法。首先回顾几个关键数学概念:

  1. Sigmoid 函数:将线性输出转换为概率
    $$\sigma(z) = \frac{1}{1+e^{-z}}$$

  2. 损失函数(对数似然损失):
    $$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)}))]$$

  3. 梯度计算
    $$\frac{\partial J(\theta)}{\partial \theta_j} = \frac{1}{m}\sum_{i=1}^m (h_\theta(x^{(i)})-y^{(i)})x_j^{(i)}$$

基于这些公式,我们可以实现自定义逻辑回归:

class CustomLogisticRegression:
    def __init__(self, lr=0.01, n_iter=1000):
        self.lr = lr
        self.n_iter = n_iter

    def sigmoid(self, z):
        return 1 / (1 + np.exp(-z))

    def fit(self, X, y):
        m, n = X.shape
        self.theta = np.zeros(n)
        self.loss_history = []

        for _ in range(self.n_iter):
            z = np.dot(X, self.theta)
            h = self.sigmoid(z)
            gradient = np.dot(X.T, (h - y)) / m
            self.theta -= self.lr * gradient

            # 计算损失
            loss = (-y * np.log(h) - (1-y)*np.log(1-h)).mean()
            self.loss_history.append(loss)

        return self

    def predict(self, X):
        return (self.sigmoid(np.dot(X, self.theta)) >= 0.5).astype(int)

# 训练自定义模型
custom_model = CustomLogisticRegression(lr=0.1, n_iter=1000)
custom_model.fit(X_train, y_train)

# 评估
custom_score = (custom_model.predict(X_test) == y_test).mean()
print(f"自定义模型准确率: {custom_score:.4f}")

模型对比与可视化

我们可以通过多种方式对比两个模型的性能:

  1. 准确率对比
  2. Sklearn 模型: 1.0
  3. 自定义模型: 1.0

  4. 决策边界可视化

import matplotlib.pyplot as plt

# 创建网格点
x_min, x_max = X_scaled[:, 0].min() - 1, X_scaled[:, 0].max() + 1
y_min, y_max = X_scaled[:, 1].min() - 1, X_scaled[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
                     np.arange(y_min, y_max, 0.02))

# 预测每个网格点
Z_sk = sk_model.predict(np.c_[xx.ravel(), yy.ravel()])
Z_sk = Z_sk.reshape(xx.shape)

Z_custom = custom_model.predict(np.c_[xx.ravel(), yy.ravel()])
Z_custom = Z_custom.reshape(xx.shape)

# 绘制决策边界
plt.figure(figsize=(12, 5))

plt.subplot(121)
plt.contourf(xx, yy, Z_sk, alpha=0.4)
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=Y, edgecolor='k')
plt.title('Sklearn 决策边界')

plt.subplot(122)
plt.contourf(xx, yy, Z_custom, alpha=0.4)
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=Y, edgecolor='k')
plt.title('自定义模型决策边界')

plt.tight_layout()
plt.show()
  1. 损失函数收敛过程
plt.plot(custom_model.loss_history)
plt.xlabel('迭代次数')
plt.ylabel('损失值')
plt.title('自定义模型损失函数收敛过程')
plt.show()

避坑指南

在实现自定义逻辑回归时,有几个常见陷阱需要注意:

  1. 学习率选择
  2. 过大:可能导致损失函数震荡甚至发散
  3. 过小:收敛速度慢
  4. 建议:从 0.01 开始尝试,观察损失函数变化

  5. 特征缩放

  6. 梯度下降对特征尺度敏感
  7. 务必进行标准化处理(如我们前面所做)

  8. 迭代终止

  9. 可以设置损失变化阈值或最大迭代次数
  10. 观察损失曲线判断是否收敛

延伸思考

读者可以尝试以下扩展实验:

  1. 使用所有 4 个特征进行训练,观察性能变化
  2. 实现 L1/L2 正则化版本
  3. 尝试不同的优化算法(如随机梯度下降、Adam 等)
  4. 处理多分类问题(使用 softmax 回归)

总结

通过这次实验,我们对比了 Sklearn 和自定义实现的逻辑回归。对于实际项目,如果追求开发效率和稳定性,Sklearn 是更好的选择;而如果想深入理解算法原理,自己实现一遍梯度下降会很有帮助。无论哪种方式,理解背后的数学原理都是至关重要的。

正文完
 0
评论(没有评论)