【Python机器学习】线性回归与逻辑回归:从原理到 Scikit-learn 实战

目录

[1. 引言:机器学习的基石------线性模型](#1. 引言:机器学习的基石——线性模型)

[2. 线性回归:预测连续值的艺术](#2. 线性回归:预测连续值的艺术)

[2.1 模型假设与数学表达](#2.1 模型假设与数学表达)

[2.2 损失函数:衡量预测误差](#2.2 损失函数:衡量预测误差)

[2.3 优化方法:求解最优系数](#2.3 优化方法:求解最优系数)

[2.3.1 解析解:正规方程](#2.3.1 解析解:正规方程)

[2.3.2 迭代优化:梯度下降](#2.3.2 迭代优化:梯度下降)

[2.4 Scikit-learn 实战:预测波士顿房价](#2.4 Scikit-learn 实战:预测波士顿房价)

[3. 逻辑回归:分类问题的桥梁](#3. 逻辑回归:分类问题的桥梁)

[3.1 模型假设与数学表达:从线性到概率](#3.1 模型假设与数学表达:从线性到概率)

[3.2 损失函数:交叉熵的威力](#3.2 损失函数:交叉熵的威力)

[3.3 优化方法:梯度下降是王道](#3.3 优化方法:梯度下降是王道)

[3.4 Scikit-learn 实战:乳腺癌二分类预测](#3.4 Scikit-learn 实战:乳腺癌二分类预测)

[4. 模型假设、损失函数与优化方法:深入比较](#4. 模型假设、损失函数与优化方法:深入比较)

[4.1 模型假设的对比](#4.1 模型假设的对比)

[4.2 损失函数的对比](#4.2 损失函数的对比)

[4.3 优化方法的对比](#4.3 优化方法的对比)

[5. AI 关联:基础模型的力量与未来](#5. AI 关联:基础模型的力量与未来)

[5.1 作为复杂模型的构建块](#5.1 作为复杂模型的构建块)

[5.2 解释性与可信赖 AI](#5.2 解释性与可信赖 AI)

[5.3 统计学与机器学习的桥梁](#5.3 统计学与机器学习的桥梁)

[5.4 广泛的实际应用](#5.4 广泛的实际应用)

[5.5 未来展望](#5.5 未来展望)

[6. 结论](#6. 结论)


1. 引言:机器学习的基石------线性模型

在人工智能和机器学习的浩瀚星空中,线性模型以其简洁、直观和强大的解释性,占据着举足轻重的地位。它们是理解更复杂模型的基础,也是许多实际应用中首选的解决方案。线性回归和逻辑回归,作为线性模型的两大代表,分别解决了连续值预测和二分类问题,其背后的数学原理和实践应用,构成了机器学习入门的必修课。本篇长文将带领读者从理论的深邃之处,一步步走向 Scikit-learn 的实践殿堂,深入剖析线性模型的核心假设、损失函数的选择、优化方法的演进,以及如何在真实世界的数据集上应用它们,并进行参数调优和结果解读。我们将不仅仅停留在模型的"是什么",更会深入探究"为什么"和"如何",力求让读者对这两个基础模型有一个全面而深刻的理解,并认识到它们在人工智能领域广泛而持久的关联性。

线性模型之所以如此重要,很大程度上源于其数学上的可解释性。与许多"黑箱"模型不同,线性模型能够清晰地展示输入特征如何影响输出结果,每个特征的权重(系数)直接反映了其贡献的大小和方向。这种可解释性在金融风控、医疗诊断、市场营销等领域尤为宝贵,因为它能帮助领域专家理解模型的决策过程,从而建立信任并进行有效的干预。此外,线性模型通常计算效率高,对大规模数据集也能表现出良好的性能,这使得它们在实时应用和资源受限的环境中具有天然的优势。

本篇文章将围绕线性回归和逻辑回归这两个核心模型展开,首先会深入探讨它们各自的理论基础,包括模型的数学表达、关键假设、损失函数的定义以及常用的优化算法。随后,我们将转向实践层面,详细介绍如何使用强大的 Scikit-learn 库来实现和应用这些模型。通过具体的代码示例,读者将学习如何加载数据、预处理特征、训练模型、评估性能以及进行超参数调优。最后,我们将对模型的输出结果进行深入解读,理解系数的含义,并探讨模型在实际 AI 应用中的广泛关联性。我们的目标是构建一个完整的学习路径,从抽象的数学概念到具体的编程实现,再到对结果的深入洞察,让读者能够真正掌握线性模型的力量。

2. 线性回归:预测连续值的艺术

线性回归是机器学习中最基本、最经典的监督学习算法之一,其核心思想是用一条直线(或高维空间中的超平面)来拟合数据点,从而预测一个连续的目标变量。它的应用场景非常广泛,例如预测房价、股票价格、销售额,或者根据学习时间预测考试成绩等等。理解线性回归,是理解许多更复杂回归模型的基础。

2.1 模型假设与数学表达

线性回归的核心在于"线性"二字。它假设目标变量y与一个或多个输入特征 之间存在线性关系。最简单的形式是简单线性回归,只有一个特征x:

y = \\beta_0 + \\beta_1 x + \\epsilon

其中:

  • y 是目标变量(因变量)。
  • x 是输入特征(自变量)。
  • 是截距项(intercept),表示当 x=0 时 y 的期望值。
  • 是斜率(slope)或系数(coefficient),表示 x 每改变一个单位,y 平均改变的量。
  • 是误差项(error term),代表模型未能解释的部分,它包含了随机噪声和未包含在模型中的其他因素的影响。

当存在多个特征时,模型扩展为多元线性回归

y = \\beta_0 + \\beta_1 x_1 + \\beta_2 x_2 + \\dots + \\beta_n x_n + \\epsilon

在矩阵形式下,这可以写得更加简洁:

\\mathbf{y} = \\mathbf{X} \\boldsymbol{\\beta} + \\boldsymbol{\\epsilon}

其中:

  • 是一个 的向量,包含 m 个观测值的目标变量。
  • X 是一个 的矩阵,其中第一列是全为 1 的列向量(对应截距项 ),其余 n 列是 m 个观测值的 n 个特征值。
  • 是一个 的向量,包含模型的系数()。
  • 是一个 的向量,包含 m 个观测值的误差项。

线性回归模型成立的关键在于其一系列假设,这些假设虽然在实际应用中可能不会完全满足,但它们指导了模型的构建和解释:

  1. 线性关系(Linearity): 目标变量 y 与特征 X 之间存在线性关系。这意味着我们选择的模型形式是正确的。
  2. 独立性(Independence) : 观测值之间是相互独立的,并且误差项之间也是相互独立的。这意味着一个观测值的误差不应影响另一个观测值的误差。
  3. 同方差性(Homoscedasticity) : 误差项 的方差在所有特征值上是恒定的,即 。这意味着误差的大小不随输入特征的变化而变化。
  4. 误差项的零均值(Zero Mean) : 误差项 的期望值为零,即。这意味着模型预测的平均值是准确的,没有系统性的偏差。
  5. 误差项的正态分布(Normality of Errors) : (此假设在参数估计和假设检验中很重要,但在模型预测本身上不是必需的)。误差项 服从正态分布。

2.2 损失函数:衡量预测误差

在线性回归中,我们的目标是找到一组最优的系数 ,使得模型预测值 与真实值 之间的差异最小。衡量这种差异最常用的损失函数是均方误差(Mean Squared Error, MSE) ,也称为**残差平方和(Sum of Squared Residuals, SSR)**的平均值。

损失函数定义为:

J(\\boldsymbol{\\beta}) = \\frac{1}{m} \\sum_{i=1}\^{m} (y_i - \\hat{y}*i)\^2 = \\frac{1}{m} \\sum*{i=1}\^{m} (y_i - (\\beta_0 + \\beta_1 x_{i1} + \\dots + \\beta_n x_{in}))\^2

或者在矩阵形式下:

我们的任务就是找到使最小的

2.3 优化方法:求解最优系数

求解使损失函数最小的系数主要有两种方法:解析解迭代优化

2.3.1 解析解:正规方程

对于均方误差损失函数,存在一个直接的解析解,称为正规方程(Normal Equation) 。通过对损失函数 关于求导,并令导数为零,我们可以得到:

\\frac{\\partial J(\\boldsymbol{\\beta})}{\\partial \\boldsymbol{\\beta}} = \\frac{2}{m} \\mathbf{X}\^T (\\mathbf{X} \\boldsymbol{\\beta} - \\mathbf{y}) = 0

\\mathbf{X}\^T (\\mathbf{X} \\boldsymbol{\\beta} - \\mathbf{y}) = 0

\\mathbf{X}\^T \\mathbf{X} \\boldsymbol{\\beta} = \\mathbf{X}\^T \\mathbf{y}

如果矩阵是可逆的(通常在特征之间不存在完全多重共线性时成立),那么我们可以直接求解

\\boldsymbol{\\beta}\^\* = (\\mathbf{X}\^T \\mathbf{X})\^{-1} \\mathbf{X}\^T \\mathbf{y}

这个公式可以直接计算出最优的系数向量。这种方法优点是直接、精确,不需要迭代。缺点是当特征数量 n 非常大时,计算的复杂度会很高(约),并且如果接近奇异,数值稳定性也会受到影响。

2.3.2 迭代优化:梯度下降

当特征数量很大,或者我们希望使用更通用的优化方法时,**梯度下降(Gradient Descent)**是一个非常有效的选择。梯度下降是一种迭代算法,它从一个随机的系数向量 \\boldsymbol{\\beta} 开始,然后沿着损失函数梯度下降最快的方向(负梯度方向)逐步更新系数,直到收敛到局部最小值(对于凸函数如 MSE,局部最小值即全局最小值)。

更新规则如下:

其中:

  • 是学习率(learning rate),控制每一步更新的步长。
  • 是损失函数 关于的梯度。

对于 MSE 损失函数,梯度为:

\\nabla_{\\boldsymbol{\\beta}} J(\\boldsymbol{\\beta}) = \\frac{2}{m} \\mathbf{X}\^T (\\mathbf{X} \\boldsymbol{\\beta} - \\mathbf{y})

因此,梯度下降的更新步骤是:

梯度下降有几种变体:

  • 批量梯度下降(Batch Gradient Descent, BGD): 在每次更新时,使用所有训练样本计算梯度。计算精确但速度慢,内存消耗大。
  • 随机梯度下降(Stochastic Gradient Descent, SGD): 在每次更新时,随机选择一个训练样本计算梯度。速度快,内存消耗小,但梯度波动大,可能不会精确收敛到最小值,而是围绕最小值波动。
  • 小批量梯度下降(Mini-batch Gradient Descent, MBGD): 在每次更新时,使用一小批(mini-batch)训练样本计算梯度。是 BGD 和 SGD 的折衷,兼顾了计算效率和收敛稳定性,是实际中最常用的方法。

Scikit-learn 的 LinearRegression 默认使用基于正规方程的优化方法(或者其高效实现),而 SGDRegressor 则提供了梯度下降的实现,允许用户选择不同的损失函数和优化策略。

2.4 Scikit-learn 实战:预测波士顿房价

为了更直观地理解线性回归,我们使用 Scikit-learn 来实现一个预测波士顿房价的例子。波士顿房价数据集是一个经典的回归问题数据集,包含 506 个样本,每个样本有 13 个特征,目标是预测房屋的中位数价格。

首先,我们需要安装 Scikit-learn 和其他必要的库:

复制代码
pip install scikit-learn pandas numpy matplotlib seaborn

然后,我们可以编写 Python 代码来加载数据、训练模型并进行预测。

复制代码
import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression, SGDRegressor
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.metrics import mean_squared_error, r2_score

# ===== 解决中文显示问题 =====
matplotlib.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']  # Windows系统用SimHei
matplotlib.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
plt.rcParams['figure.dpi'] = 100

# --- 1. 数据加载与准备 ---
print("加载加州房价数据集...")
housing = fetch_california_housing()
X = pd.DataFrame(housing.data, columns=housing.feature_names)
y = pd.Series(housing.target, name='MedHouseVal')
print("数据集加载成功。")

# 查看数据的前几行
print("\n数据前5行:")
print(X.head())
print("\n目标变量前5行:")
print(y.head())
print(f"\n数据集形状: {X.shape}")
print(f"目标变量形状: {y.shape}")

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

print(f"\n训练集样本数: {X_train.shape[0]}")
print(f"测试集样本数: {X_test.shape[0]}")

# --- 2. 模型训练 - LinearRegression ---
model = LinearRegression()

print("\n" + "="*60)
print("开始训练 LinearRegression 模型...")
model.fit(X_train, y_train)
print("LinearRegression 模型训练完成。")

# --- 3. 模型评估 - LinearRegression ---
y_pred = model.predict(X_test)

mse = mean_squared_error(y_test, y_pred)
print(f"\n测试集上的均方误差 (MSE): {mse:.4f}")

r2 = r2_score(y_test, y_pred)
print(f"测试集上的 R2 分数: {r2:.4f}")

rmse = np.sqrt(mse)
print(f"测试集上的均方根误差 (RMSE): {rmse:.4f}")

# --- 4. 参数解读 ---
intercept = model.intercept_
print(f"\n模型截距项 (beta_0): {intercept:.4f}")

coefficients = model.coef_
print("\n模型系数 (beta_1, beta_2, ...):")
coeff_df = pd.DataFrame({'Feature': X.columns, 'Coefficient': coefficients})
print(coeff_df)

# --- 5. 可视化与分析 ---
# 绘制预测值与真实值的散点图
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.5, edgecolors='w', s=30)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
plt.xlabel("真实值 (Actual Values)", fontsize=12)
plt.ylabel("预测值 (Predicted Values)", fontsize=12)
plt.title("LinearRegression - 真实值 vs 预测值", fontsize=14, fontweight='bold')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

# 绘制残差图
residuals = y_test - y_pred
plt.figure(figsize=(10, 6))
plt.scatter(y_pred, residuals, alpha=0.5, edgecolors='w', s=30)
plt.axhline(y=0, color='r', linestyle='--', lw=2)
plt.xlabel("预测值 (Predicted Values)", fontsize=12)
plt.ylabel("残差 (Residuals)", fontsize=12)
plt.title("LinearRegression - 残差图", fontsize=14, fontweight='bold')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

# 绘制特征系数的条形图
plt.figure(figsize=(12, 7))
coeff_sorted = coeff_df.sort_values('Coefficient', ascending=True)
colors = ['red' if x < 0 else 'green' for x in coeff_sorted['Coefficient']]
plt.barh(coeff_sorted['Feature'], coeff_sorted['Coefficient'], color=colors, alpha=0.7)
plt.title('LinearRegression - 特征系数', fontsize=14, fontweight='bold')
plt.xlabel('系数大小', fontsize=12)
plt.ylabel('特征', fontsize=12)
plt.grid(True, alpha=0.3, axis='x')
plt.tight_layout()
plt.show()

# --- 6. 使用 SGDRegressor 进行演示 ---
print("\n" + "="*60)
print("开始训练 SGDRegressor 模型...")

sgd_model = make_pipeline(StandardScaler(),
                          SGDRegressor(loss='squared_error',
                                       max_iter=1000,
                                       tol=1e-3,
                                       random_state=42,
                                       early_stopping=False))

sgd_model.fit(X_train, y_train)
print("SGDRegressor 模型训练完成。")

# 评估 SGDRegressor 模型性能
y_pred_sgd = sgd_model.predict(X_test)

mse_sgd = mean_squared_error(y_test, y_pred_sgd)
r2_sgd = r2_score(y_test, y_pred_sgd)
rmse_sgd = np.sqrt(mse_sgd)

print(f"\nSGDRegressor 测试集上的均方误差 (MSE): {mse_sgd:.4f}")
print(f"SGDRegressor 测试集上的 R2 分数: {r2_sgd:.4f}")
print(f"SGDRegressor 测试集上的均方根误差 (RMSE): {rmse_sgd:.4f}")

# 获取SGDRegressor的系数
sgd_coefficients = sgd_model.steps[1][1].coef_
sgd_intercept = sgd_model.steps[1][1].intercept_

print(f"\nSGDRegressor 模型截距项: {sgd_intercept:.4f}")
print("\nSGDRegressor 模型系数:")
sgd_coeff_df = pd.DataFrame({'Feature': X.columns, 'Coefficient': sgd_coefficients})
print(sgd_coeff_df)

# --- 7. 对比两个模型 ---
print("\n" + "="*60)
print("模型对比总结:")
print("-" * 60)
comparison_df = pd.DataFrame({
    'Model': ['LinearRegression', 'SGDRegressor'],
    'MSE': [mse, mse_sgd],
    'RMSE': [rmse, rmse_sgd],
    'R2': [r2, r2_sgd]
})
print(comparison_df)
print("\n说明:")
print("- LinearRegression 使用正规方程求解,一次性求得最优解")
print("- SGDRegressor 使用随机梯度下降进行迭代优化")
print("- 通常在数据量不大的情况下,两者结果会非常接近")
print("- 在大规模数据中,SGDRegressor 因为计算效率更高而更常用")

# 绘制两个模型的预测值对比
fig, axes = plt.subplots(1, 2, figsize=(16, 6))

# LinearRegression
axes[0].scatter(y_test, y_pred, alpha=0.5, edgecolors='w', s=30)
axes[0].plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
axes[0].set_xlabel("真实值", fontsize=12)
axes[0].set_ylabel("预测值", fontsize=12)
axes[0].set_title(f"LinearRegression (R2={r2:.4f})", fontsize=13, fontweight='bold')
axes[0].grid(True, alpha=0.3)

# SGDRegressor
axes[1].scatter(y_test, y_pred_sgd, alpha=0.5, edgecolors='w', s=30)
axes[1].plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
axes[1].set_xlabel("真实值", fontsize=12)
axes[1].set_ylabel("预测值", fontsize=12)
axes[1].set_title(f"SGDRegressor (R2={r2_sgd:.4f})", fontsize=13, fontweight='bold')
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# 绘制两个模型的残差对比
fig, axes = plt.subplots(1, 2, figsize=(16, 6))

residuals_linear = y_test - y_pred
axes[0].scatter(y_pred, residuals_linear, alpha=0.5, edgecolors='w', s=30)
axes[0].axhline(y=0, color='r', linestyle='--', lw=2)
axes[0].set_xlabel("预测值", fontsize=12)
axes[0].set_ylabel("残差", fontsize=12)
axes[0].set_title("LinearRegression - 残差图", fontsize=13, fontweight='bold')
axes[0].grid(True, alpha=0.3)

residuals_sgd = y_test - y_pred_sgd
axes[1].scatter(y_pred_sgd, residuals_sgd, alpha=0.5, edgecolors='w', s=30)
axes[1].axhline(y=0, color='r', linestyle='--', lw=2)
axes[1].set_xlabel("预测值", fontsize=12)
axes[1].set_ylabel("残差", fontsize=12)
axes[1].set_title("SGDRegressor - 残差图", fontsize=13, fontweight='bold')
axes[1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

print("\n" + "="*60)
print("所有可视化图表已生成!")
print("="*60)

在这个实战案例中,我们完成了以下步骤:

  1. 数据加载与准备: 加载波士顿房价数据集,将其划分为训练集和测试集。
  2. 模型训练 : 初始化 LinearRegression 模型,并使用训练集 fit() 方法进行训练。
  3. 模型评估 : 使用测试集 predict() 方法获取预测值,然后计算 MSE 和 R² 分数来评估模型性能。
  4. 参数解读 : 查看模型的截距项 intercept_ 和系数 coef_,并分析它们的含义。
  5. 可视化: 绘制了真实值与预测值的散点图、残差图以及特征系数的条形图,以更直观地理解模型表现和特征重要性。
  6. SGDRegressor 演示 : 展示了如何使用 SGDRegressor,以及它与 LinearRegression 的区别和联系,包括数据标准化和管道的使用。

通过这个例子,读者可以清晰地看到如何从理论走向实践,使用 Scikit-learn 快速构建和评估一个线性回归模型。

3. 逻辑回归:分类问题的桥梁

与线性回归用于预测连续值不同,逻辑回归(Logistic Regression) 虽然名字里有"回归",但它实际上是一个用于分类 任务的算法,尤其擅长处理二分类问题。它通过一个巧妙的函数将线性模型的输出映射到概率值,从而实现类别的预测。

3.1 模型假设与数学表达:从线性到概率

逻辑回归同样建立在线性模型的基础上,但目标变量 y 是离散的类别标签(例如 0 或 1)。假设我们有一个线性模型:

z = \\beta_0 + \\beta_1 x_1 + \\beta_2 x_2 + \\dots + \\beta_n x_n

直接将 z 作为类别标签(例如 z > 0 为类别 1, 为类别 0)会存在一些问题:

  1. 不连续性: 边界处的微小变化会导致类别发生剧烈跳变,不够平滑。
  2. 无法解释为概率: z 的值可以是任意实数,无法直接解释为属于某个类别的概率。

为了解决这些问题,逻辑回归引入了Sigmoid 函数(或 Logistic 函数),它将任意实数映射到 (0, 1) 区间:

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

Sigmoid 函数的形状是"S"型的,当 z 趋于正无穷时, 趋于 1;当 z 趋于负无穷时, 趋于 0;当 z=0 时,=0.5。

逻辑回归模型将线性模型的输出 z 输入到 Sigmoid 函数中,得到属于类别 1 的概率:

P(y=1 \| \\mathbf{x}; \\boldsymbol{\\beta}) = \\sigma(\\mathbf{x}\^T \\boldsymbol{\\beta}) = \\frac{1}{1 + e\^{-(\\beta_0 + \\beta_1 x_1 + \\dots + \\beta_n x_n)}}

其中 是包含特征值和常数 1 的特征向量, 是对应的系数向量。

那么,属于类别 0 的概率自然就是:

P(y=0 \| \\mathbf{x}; \\boldsymbol{\\beta}) = 1 - P(y=1 \| \\mathbf{x}; \\boldsymbol{\\beta}) = 1 - \\sigma(\\mathbf{x}\^T \\boldsymbol{\\beta})

通过设定一个概率阈值(通常是 0.5),我们可以进行分类:

  • 如果,则预测为类别 1。
  • 如果 ,则预测为类别 0。

注意,当时,概率大于 0.5;当时,概率小于 0.5;当时,概率等于 0.5。因此,逻辑回归的决策边界(Decision Boundary)仍然是线性的,即

逻辑回归的假设与线性回归类似,但主要针对概率和分类:

  1. 二元输出: 目标变量是二元的(0 或 1)。
  2. 线性关系: 特征与 log-odds(对数几率)之间存在线性关系。log-odds 定义为$$\log\left(\frac{P(y=1|x)}{1-P(y=1|x)}\right) = \mathbf{x}^T \boldsymbol{\beta}$$
  3. 独立性: 观测值之间是相互独立的。
  4. 无多重共线性: 特征之间不应存在高度相关性。

3.2 损失函数:交叉熵的威力

与线性回归使用 MSE 作为损失函数不同,逻辑回归通常使用交叉熵(Cross-Entropy) 损失函数,也称为对数损失(Log Loss)。这是因为 Sigmoid 函数的输出是概率,MSE 损失函数在这种情况下不再是凸函数,优化会变得困难。交叉熵损失函数能够更好地衡量预测概率与真实标签之间的差异。

对于单个样本 (x, y),交叉熵损失函数定义为:

L(y, \\hat{y}) = -\[y \\log(\\hat{y}) + (1-y) \\log(1-\\hat{y})\]

如果 y=1,损失为 。当 接近 1 时,损失接近 0;当接近 0 时,损失趋于无穷大。

如果 y=0,损失为。当 接近 0 时,接近 1,损失接近 0;当 接近 1 时,接近 0,损失趋于无穷大。

对于所有m个训练样本,总的交叉熵损失函数是所有样本损失的平均值:

J(\\boldsymbol{\\beta}) = -\\frac{1}{m} \\sum_{i=1}\^{m} \[y\^{(i)} \\log(\\hat{y}\^{(i)}) + (1-y\^{(i)}) \\log(1-\\hat{y}\^{(i)})\]

其中 $$\hat{y}^{(i)} = \sigma(\mathbf{x}^{(i)T} \boldsymbol{\beta}).$$

3.3 优化方法:梯度下降是王道

逻辑回归的损失函数是关于的凸函数,因此可以使用梯度下降法来找到全局最小值。与线性回归类似,我们需要计算损失函数关于的梯度。

经过推导(这里不展开详细推导过程),交叉熵损失函数的梯度为:

\\nabla_{\\boldsymbol{\\beta}} J(\\boldsymbol{\\beta}) = \\frac{1}{m} \\mathbf{X}\^T (\\boldsymbol{\\sigma}(\\mathbf{X} \\boldsymbol{\\beta}) - \\mathbf{y})

其中 是对向量的每个元素应用 Sigmoid 函数的结果,是真实标签向量。

梯度下降的更新规则与线性回归相同:

Scikit-learn 的 LogisticRegression 类默认使用基于拟牛顿法(如 L-BFGS)的优化器,这种优化器通常比梯度下降收敛更快,但也有其他求解器可供选择,包括基于 SGD 的优化。

3.4 Scikit-learn 实战:乳腺癌二分类预测

我们使用 Scikit-learn 来演示逻辑回归在乳腺癌诊断数据集上的应用。这个数据集包含 569 个样本,每个样本有 30 个特征,目标是预测肿瘤是良性(0)还是恶性(1)。

复制代码
import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib
# ===== 解决中文显示问题 =====
matplotlib.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']  # Windows系统用SimHei
matplotlib.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题
plt.rcParams['figure.dpi'] = 100
# --- 1. 数据加载与准备 ---
# 加载乳腺癌数据集
cancer = load_breast_cancer()
X = pd.DataFrame(cancer.data, columns=cancer.feature_names)
y = pd.Series(cancer.target, name='target') # 0: malignant (恶性), 1: benign (良性)
# 在 Scikit-learn 中,通常将主要关注的类别设为 1。
# 这里的 'target' 0代表恶性,1代表良性。
# 为了方便理解,我们可能需要调整标签或在解读时注意。
# 让我们保持原始标签,并在报告中说明。
print("乳腺癌数据集加载成功。")
print(f"特征数量: {X.shape[1]}")
print(f"样本数量: {X.shape[0]}")
print(f"类别分布:malignant (0): {np.sum(y == 0)}, benign (1): {np.sum(y == 1)}")


# 查看数据的前几行
print("\n数据前5行:")
print(X.head())

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y) # stratify=y 保证类别比例在划分后保持一致

print(f"\n训练集样本数: {X_train.shape[0]}")
print(f"测试集样本数: {X_test.shape[0]}")

# --- 2. 模型训练 ---
# 初始化逻辑回归模型
# Scikit-learn 的 LogisticRegression 默认使用 L-BFGS 求解器
# C 是正则化强度的倒数,值越小,正则化越强
# penalty='l2' 是 L2 正则化,常用于逻辑回归,防止过拟合
# solver='lbfgs' 是默认的优化算法
# random_state 用于重现性
model = LogisticRegression(C=1.0, penalty='l2', solver='lbfgs', random_state=42, max_iter=1000)

# 逻辑回归也对特征尺度敏感,尤其是在使用正则化时。
# 通常需要对特征进行标准化。
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline

# 创建一个包含标准化和逻辑回归的管道
pipeline = make_pipeline(StandardScaler(),
                         LogisticRegression(C=1.0, penalty='l2', solver='lbfgs', random_state=42, max_iter=1000))

# 使用训练集训练模型
print("\n开始训练逻辑回归模型 (含标准化)...")
pipeline.fit(X_train, y_train)
print("模型训练完成。")

# --- 3. 模型评估 ---
# 使用测试集进行预测
y_pred = pipeline.predict(X_test)

# 评估模型性能
# 准确率 (Accuracy)
accuracy = accuracy_score(y_test, y_pred)
print(f"\n测试集上的准确率: {accuracy:.4f}")

# 混淆矩阵 (Confusion Matrix)
# True Positives (TP), False Positives (FP)
# False Negatives (FN), True Negatives (TN)
# 在本例中,target 0 (malignant) 是负类,1 (benign) 是正类。
# 混淆矩阵表示:
# [[TN, FP],
#  [FN, TP]]
# TN: 真实为负,预测为负 (真实恶性,预测恶性)
# FP: 真实为正,预测为负 (真实良性,预测恶性) - Type I error
# FN: 真实为负,预测为正 (真实恶性,预测良性) - Type II error
# TP: 真实为正,预测为正 (真实良性,预测良性)
cm = confusion_matrix(y_test, y_pred)
print("\n混淆矩阵:")
print(cm)

# 分类报告 (Classification Report)
# 包含精确率 (Precision)、召回率 (Recall)、F1 分数 (F1-score) 和支持度 (Support)
# Precision = TP / (TP + FP) (预测为正的样本中,有多少是真正的正样本)
# Recall = TP / (TP + FN) (所有真正的正样本中,有多少被正确预测出来)
# F1-score = 2 * (Precision * Recall) / (Precision + Recall) (Precision 和 Recall 的调和平均数)
# Support 是每个类别的实际样本数
print("\n分类报告:")
# target_names 映射回实际的类别名称,方便理解
target_names = [cancer.target_names[i] for i in range(len(cancer.target_names))]
print(classification_report(y_test, y_pred, target_names=target_names))

# --- 4. 参数解读 ---
# 查看模型的截距项和系数
# 由于使用了管道,我们需要先获取 LogisticRegression 模型对象
log_reg_model = pipeline.named_steps['logisticregression']
intercept = log_reg_model.intercept_
coefficients = log_reg_model.coef_

print(f"\n模型截距项: {intercept[0]:.4f}") # 截距项通常是单个值
print("\n模型系数:")
coeff_df = pd.DataFrame({'Feature': X.columns, 'Coefficient': coefficients[0]}) # 系数是二维数组,取第一行
print(coeff_df.sort_values('Coefficient', ascending=False))

# 解释:
# 截距项表示当所有特征的标准化值为 0 时,log-odds 的值。
# 系数表示在其他特征标准化值不变的情况下,该特征标准化值每增加一个单位,
# log-odds 的变化量。
# 正系数表示该特征与属于类别 1(良性)的概率正相关。
# 负系数表示该特征与属于类别 1(良性)的概率负相关,即与属于类别 0(恶性)的概率正相关。
# 系数的大小(绝对值)表示了该特征在模型中的相对重要性。

# --- 5. 可视化与分析 ---
# 绘制混淆矩阵的热力图
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=target_names, yticklabels=target_names)
plt.xlabel('预测标签 (Predicted Label)')
plt.ylabel('真实标签 (True Label)')
plt.title('混淆矩阵 (Confusion Matrix)')
plt.show()

# 绘制特征系数的条形图
plt.figure(figsize=(12, 8))
sns.barplot(x='Coefficient', y='Feature', data=coeff_df.sort_values('Coefficient', ascending=False), palette='viridis')
plt.title('逻辑回归模型特征系数 (标准化后)')
plt.xlabel('系数大小 (Log-odds change per unit feature increase)')
plt.ylabel('特征')
plt.show()

# --- 6. 预测概率 ---
# predict_proba() 方法返回每个类别的概率
y_pred_proba = pipeline.predict_proba(X_test)
print("\n测试集上的预测概率 (前5个样本):")
# 格式为 [[P(y=0), P(y=1)], ...]
print(y_pred_proba[:5])

# 我们可以根据阈值 0.5 来解释这些概率
# 例如,如果 P(y=1) > 0.5,则预测为 1 (benign)
# 这种阈值可以根据业务需求进行调整,例如在医疗诊断中,可能更愿意接受假阳性(将恶性预测为良性)的风险,
# 而不是假阴性(将良性预测为恶性),这时可以降低阈值。

# 绘制 P(y=1) 的分布图
plt.figure(figsize=(10, 6))
sns.histplot(y_pred_proba[:, 1], bins=20, kde=True, color='skyblue')
plt.axvline(0.5, color='red', linestyle='--', lw=2, label='Decision Threshold (0.5)')
plt.xlabel("预测为良性 (Class 1) 的概率")
plt.ylabel("样本数")
plt.title("逻辑回归预测概率分布")
plt.legend()
plt.show()

在这个逻辑回归的实战案例中,我们展示了:

  1. 数据加载与准备 : 加载乳腺癌数据集,并使用 stratify=y 进行分层抽样,以保持类别比例。
  2. 模型训练 : 引入 StandardScaler 进行特征标准化,并构建了一个包含标准化和 LogisticRegression 的管道 (Pipeline)。LogisticRegressionC 参数控制正则化强度,penalty 参数指定正则化类型(通常是 'l2')。
  3. 模型评估 : 使用 accuracy_score 计算准确率,confusion_matrix 绘制混淆矩阵,以及 classification_report 提供更详细的精确率、召回率和 F1 分数。
  4. 参数解读: 分析模型的截距项和标准化后的特征系数,理解它们对 log-odds 和最终概率的影响。
  5. 可视化: 绘制了混淆矩阵热力图和特征系数条形图。
  6. 预测概率 : 使用 predict_proba 方法获取每个类别的预测概率,并展示了概率分布图。

通过这个案例,读者可以理解逻辑回归如何处理分类问题,如何通过概率输出进行决策,以及如何使用 Scikit-learn 进行模型的训练、评估和解释。

4. 模型假设、损失函数与优化方法:深入比较

线性回归和逻辑回归虽然在应用场景和输出上有所不同,但它们在模型假设、损失函数和优化方法上有着紧密的联系和重要的区别。理解这些差异,有助于我们更灵活地选择和应用模型。

4.1 模型假设的对比

假设 线性回归 逻辑回归
目标变量 连续值 () 离散类别(通常是二元的
关系 y 与特征 x 之间存在线性关系 特征x与log-odds 之间存在线性关系
误差项 (同方差性), 独立性, (有时假设正态分布)。 假设模型输出为概率P(y=1)
决策边界 无明确的决策边界,预测值是连续的。 决策边界是线性的 ()。

关键区别 : 线性回归直接假设目标变量是线性的,而逻辑回归则假设目标变量的对数几率是线性的。这种区别是它们分别适用于回归和分类问题的根本原因。同时,线性回归对误差项的假设(如同方差性、正态性)在参数估计和假设检验中至关重要,而逻辑回归则关注概率的建模。

4.2 损失函数的对比

模型 常用损失函数 数学表达式 (单样本) 目的
线性回归 均方误差 (MSE) / 残差平方和 (SSR) 最小化预测值与真实值之间的平方差, 直接衡量预测的"距离"有多远。
逻辑回归 交叉熵 (Cross-Entropy) / 对数损失 (Log Loss) 衡量预测概率分布与真实标签分布 之间的差异。当真实标签为 1 时, 鼓励预测概率接近 1;当真实标签为 0 时,鼓励预测概率接近 0。

关键区别: MSE 损失函数直接关注预测值与真实值之间的数值差异,而交叉熵损失函数则关注预测概率与真实标签之间的"信息量"差异。对于概率模型,交叉熵是更自然、更有效的损失函数,因为它能够惩罚模型预测概率与真实结果之间的不匹配程度,并且其凸性也使得优化更加容易。

4.3 优化方法的对比

模型 主要优化方法 梯度表达式 (MSE for Linear Regression) 梯度表达式 (Cross-Entropy for Logistic Regression)
线性回归 正规方程 (Normal Equation) , 梯度下降 N/A
逻辑回归 梯度下降 (及其变体), 拟牛顿法 (如 L-BFGS) N/A

关键区别:

  • 解析解: 线性回归的 MSE 损失函数可以通过正规方程获得解析解,这在特征数量不多时非常高效。逻辑回归的交叉熵损失函数没有简单的解析解,必须依赖迭代优化。
  • 迭代优化 : 对于大规模数据或高维特征,梯度下降(及其变体如 SGD、Mini-batch GD)是两种模型都适用的通用优化方法。Scikit-learn 的 LogisticRegression 默认使用的 L-BFGS 等拟牛顿法通常比标准的梯度下降收敛更快。
  • 梯度形式 : 尽管形式上不同,但逻辑回归的梯度可以看作是误差项 与特征矩阵 X的乘积。这与线性回归梯度中的误差项有着结构上的相似性。

正则化 (Regularization)

在线性模型中,为了防止过拟合,我们常常引入正则化。

  • L1 正则化 (Lasso): 在损失函数中添加系数绝对值之和 \\sum \|\\beta_i\|。倾向于使一些系数变为零,起到特征选择的作用。
  • L2 正则化 (Ridge): 在损失函数中添加系数平方和 \\sum \\beta_i\^2。倾向于使系数趋向于零,但很少使其变为精确的零。

在 Scikit-learn 中:

  • LinearRegression 没有内置正则化,但 RidgeLasso 类提供了带 L2 和 L1 正则化的线性回归。
  • LogisticRegression 内置了 L2 正则化(penalty='l2'),并且可以通过 C 参数控制正则化强度(C 越小,正则化越强)。也可以选择 L1 正则化 (penalty='l1'),但需要配合支持 L1 的 solver,如 'liblinear''saga'

理解这些优化方法的原理和适用场景,可以帮助我们选择最适合特定问题和数据集的模型实现。

5. AI 关联:基础模型的力量与未来

线性模型,特别是线性回归和逻辑回归,虽然看似简单,却在人工智能的广阔领域中扮演着不可或缺的角色。它们不仅是机器学习入门的基石,更是许多复杂模型的基础模块,以及许多实际应用场景下的首选方案。

5.1 作为复杂模型的构建块

许多先进的机器学习模型,如神经网络、支持向量机(SVM)等,在其底层结构中都包含了线性模型的思想。例如,神经网络中的全连接层本质上就是一系列的线性变换(加权求和)后接一个非线性激活函数。逻辑回归的 Sigmoid 函数和交叉熵损失函数,在神经网络中也被广泛用作输出层激活函数和损失函数,用于处理二分类问题。深度学习模型通过堆叠多个这样的线性(加权求和)和非线性(激活函数)层,能够学习到数据中极其复杂的非线性模式。

5.2 解释性与可信赖 AI

在当今强调模型可解释性和可信赖性的时代,线性模型因其固有的透明度而备受青睐。在金融领域,线性模型被用于信用评分、欺诈检测,模型的系数可以直接解释为各因素对违约概率或欺诈风险的影响程度。在医疗领域,它们可以帮助医生理解哪些生理指标与疾病的发生或治疗效果相关。这种"白盒"特性使得线性模型在需要解释决策依据、满足监管要求或进行科学研究的场景中具有显著优势。

5.3 统计学与机器学习的桥梁

线性回归和逻辑回归是统计学和机器学习领域的重要交叉点。统计学家早已在使用这些模型进行推断(Inference),例如估计参数的置信区间、检验假设等。机器学习则更侧重于预测(Prediction),通过优化模型来最小化预测误差。Scikit-learn 等库的出现,极大地简化了这些模型的实现和应用,使得研究人员和工程师能够快速地将统计学理论应用于实际问题。

5.4 广泛的实际应用

  • 经济学与金融学: 预测股票价格、分析市场趋势、评估信贷风险、预测通货膨胀率。
  • 医学与生物学: 预测疾病发生概率、分析基因表达与疾病的关系、评估药物疗效。
  • 市场营销: 预测客户购买行为、评估广告投放效果、进行客户细分。
  • 社会科学: 分析人口统计数据、预测选举结果、研究社会现象的影响因素。
  • 工程领域: 预测设备故障率、优化生产流程、分析传感器数据。

这些模型之所以能够广泛应用,不仅在于它们的数学基础,还在于它们易于理解、实现和部署的特点。即使在面对非线性问题时,通过特征工程(如多项式特征、交互特征)或将它们作为集成学习(如随机森林、梯度提升树)的基础模型,线性模型也能发挥出强大的作用。

5.5 未来展望

尽管深度学习模型在图像识别、自然语言处理等领域取得了惊人的成就,但线性模型并未因此过时。相反,它们在以下方面仍然具有重要价值:

  • 基线模型: 在尝试复杂模型之前,总是建议先构建一个简单的线性模型作为基线,以衡量复杂模型的改进程度。
  • 资源受限环境: 对于计算资源有限的设备(如嵌入式系统),线性模型是理想的选择。
  • 小数据集: 在训练数据量较小的情况下,复杂的模型容易过拟合,而正则化良好的线性模型可能表现更佳。
  • 可解释性需求: 当模型的可解释性比预测精度更重要时,线性模型是首选。

未来,线性模型可能会与更先进的技术结合,例如在强化学习中用于值函数近似,或作为图神经网络中的节点或边特征的聚合器。它们简洁而强大的数学框架,使其能够适应不断发展的人工智能技术。

6. 结论

线性回归和逻辑回归,作为机器学习中最基础但应用最为广泛的模型,为我们理解数据、进行预测和分类提供了强大的工具。我们从它们的数学原理出发,深入探讨了模型假设、损失函数和优化方法,并通过 Scikit-learn 的详细实战案例,展示了如何在实际数据上应用它们,并对模型进行评估和解读。

线性回归以其对连续变量的预测能力,为我们揭示了变量之间的线性关系,其简洁的正规方程解法和灵活的梯度下降优化,使其在众多回归问题中脱颖而出。而逻辑回归,虽然名字带有"回归",却巧妙地利用 Sigmoid 函数和交叉熵损失,成功地将线性模型的输出转化为概率,解决了二分类难题。

Scikit-learn 提供的强大接口,极大地降低了这些模型的实现门槛,使得我们可以专注于数据理解、特征工程和模型调优。从波士顿房价预测到乳腺癌诊断,这些案例不仅展示了模型的应用,更强调了数据预处理(如标准化)、模型评估指标(如 MSE, R², Accuracy, Confusion Matrix)和参数解读的重要性。

最终,线性模型的力量在于它们的简洁、可解释性和广泛的适用性。它们是理解更复杂模型(如神经网络)的基石,是统计学与机器学习之间重要的桥梁,也是在许多实际应用场景下,简单却有效的解决方案。掌握了线性回归和逻辑回归,就如同掌握了打开更广阔人工智能世界的一把关键钥匙。它们的基础性,恰恰是其生命力长青的根本原因,在人工智能的持续演进中,它们将继续发挥着不可替代的作用。

相关推荐
郝学胜-神的一滴3 小时前
机器学习数据集完全指南:从公开资源到Sklearn实战
人工智能·python·程序人生·机器学习·scikit-learn·sklearn
过期的秋刀鱼!1 天前
week3-机器学习-逻辑回归模型介绍和决策边界
人工智能·机器学习·逻辑回归
Elaine3362 天前
【基于 Scikit-learn 本地数据集的垂直领域词云生成】
python·机器学习·nlp·scikit-learn·词云
中科院提名者2 天前
KNN实战进阶:模型评估、Scikit-learn实现与Numpy手动编码
python·numpy·scikit-learn
python机器学习ML3 天前
论文复现-以动物图像分类为例进行多模型性能对比分析
人工智能·python·神经网络·机器学习·计算机视觉·scikit-learn·sklearn
likerhood5 天前
4. pytorch线性回归
人工智能·pytorch·线性回归
光羽隹衡6 天前
机械学习逻辑回归——银行贷款案例
算法·机器学习·逻辑回归
deephub6 天前
Scikit-Learn 1.8引入 Array API,支持 PyTorch 与 CuPy 张量的原生 GPU 加速
人工智能·pytorch·python·机器学习·scikit-learn
Pyeako6 天前
机器学习--逻辑回归相关案例
人工智能·python·机器学习·逻辑回归·下采样·交叉验证·过采样