共计 3852 个字符,预计需要花费 10 分钟才能阅读完成。
1. 背景介绍
逻辑回归是一种广泛应用于二分类问题的统计方法,尽管名字中带有 ” 回归 ”,但它实际上是一种分类算法。它的核心思想是通过 sigmoid 函数将线性回归的输出映射到 0 和 1 之间,从而得到样本属于某一类的概率。

逻辑回归的主要优势包括:
- 算法简单,计算效率高
- 输出具有概率意义
- 容易实现和解释
- 对线性可分数据表现良好
在医疗诊断、信用评分、垃圾邮件过滤等领域都有广泛应用。
2. 数据准备
2.1 生成示例数据
我们先创建一个简单的二维数据集,方便可视化理解:
% 生成两类数据
rng(1); % 设置随机种子确保结果可重复
class1 = [1.5 + randn(50,1), 1.5 + randn(50,1)];
class2 = [-1.5 + randn(50,1), -1.5 + randn(50,1)];
% 合并数据并添加偏置项
X = [ones(100,1), [class1; class2]];
y = [ones(50,1); zeros(50,1)];
% 可视化数据
figure;
scatter(X(y==1,2), X(y==1,3), 'r', 'filled'); hold on;
scatter(X(y==0,2), X(y==0,3), 'b', 'filled');
xlabel('特征 1'); ylabel('特征 2');
legend('类别 1','类别 0'); title('原始数据分布');
2.2 数据归一化
虽然对于这个简单例子归一化不是必须的,但良好的习惯是对数据进行标准化处理:
% 标准化数据(不包括偏置列)mu = mean(X(:,2:end));
sigma = std(X(:,2:end));
X_norm = [ones(size(X,1),1), (X(:,2:end)-mu)./sigma];
3. 核心算法实现
3.1 Sigmoid 函数
逻辑回归的核心是 sigmoid 函数,它将任意实数映射到 (0,1) 区间:
$$ g(z) = \frac{1}{1 + e^{-z}} $$
MATLAB 实现:
function g = sigmoid(z)
% 计算 sigmoid 函数
% 输入:z - 可以是标量、向量或矩阵
% 输出:g - 与 z 同维度的 sigmoid 计算结果
g = 1./(1 + exp(-z));
end
3.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)}))] $$
梯度计算:
$$ \frac{\partial J(\theta)}{\partial \theta_j} = \frac{1}{m}\sum_{i=1}^m (h_\theta(x^{(i)}) – y^{(i)})x_j^{(i)} $$
MATLAB 实现:
function [J, grad] = costFunction(theta, X, y)
% 计算逻辑回归的代价和梯度
% 输入:% theta - 模型参数(n×1 向量)
% X - 特征矩阵(m×n, 包含偏置项)
% y - 真实标签(m×1 向量)
% 输出:% J - 当前参数下的代价
% grad - 梯度向量(n×1)
m = length(y); % 样本数
J = 0;
grad = zeros(size(theta));
h = sigmoid(X * theta); % 计算预测概率
% 计算代价
J = (-1/m) * sum(y.*log(h) + (1-y).*log(1-h));
% 计算梯度
grad = (1/m) * (X' * (h - y));
end
3.3 梯度下降优化
使用 MATLAB 的优化函数 fminunc 进行参数优化:
% 初始化参数
initial_theta = zeros(size(X_norm,2),1);
% 设置优化选项
options = optimset('GradObj', 'on', 'MaxIter', 400);
% 运行优化
[theta, cost] = fminunc(@(t)(costFunction(t, X_norm, y)), initial_theta, options);
% 输出最优参数
fprintf('最优参数 theta:\n');
fprintf('%f \n', theta);
3.4 绘制决策边界
决策边界是 $\theta^T x = 0$ 的地方,对于二维特征:
$$ \theta_0 + \theta_1 x_1 + \theta_2 x_2 = 0 $$
可以解出:
$$ x_2 = -\frac{\theta_0 + \theta_1 x_1}{\theta_2} $$
绘制代码:
% 绘制决策边界
plot_x = [min(X_norm(:,2))-0.5, max(X_norm(:,2))+0.5];
plot_y = (-1./theta(3)) .* (theta(2).*plot_x + theta(1));
% 注意要将归一化的特征转换回原始尺度
plot_x_orig = plot_x * sigma(1) + mu(1);
plot_y_orig = plot_y * sigma(2) + mu(2);
figure;
scatter(X(y==1,2), X(y==1,3), 'r', 'filled'); hold on;
scatter(X(y==0,2), X(y==0,3), 'b', 'filled');
plot(plot_x_orig, plot_y_orig, 'LineWidth', 2);
xlabel('特征 1'); ylabel('特征 2');
legend('类别 1','类别 0','决策边界'); title('分类结果');
4. 结果分析
4.1 预测准确率
% 计算训练集上的预测准确率
p = predict(theta, X_norm);
fprintf('训练准确率: %f%%\n', mean(double(p == y)) * 100);
function p = predict(theta, X)
% 预测函数
% 输入:% theta - 模型参数
% X - 特征矩阵(包含偏置项)
% 输出:% p - 预测类别(0 或 1)
p = round(sigmoid(X * theta));
end
4.2 混淆矩阵
% 计算混淆矩阵
predictions = predict(theta, X_norm);
TP = sum((predictions == 1) & (y == 1));
FP = sum((predictions == 1) & (y == 0));
TN = sum((predictions == 0) & (y == 0));
FN = sum((predictions == 0) & (y == 1));
confusion_matrix = [TP, FP; FN, TN];
fprintf('混淆矩阵:\n');
disp(confusion_matrix);
% 计算精确率、召回率和 F1 分数
precision = TP / (TP + FP);
recall = TP / (TP + FN);
F1 = 2 * precision * recall / (precision + recall);
fprintf('精确率: %.2f%%\n', precision*100);
fprintf('召回率: %.2f%%\n', recall*100);
fprintf('F1 分数: %.2f%%\n', F1*100);
5. 避坑指南
- 学习率选择不当
- 问题:学习率太大导致无法收敛,太小导致收敛过慢
-
解决:尝试不同的学习率(如 0.01, 0.03, 0.1, 0.3),观察代价函数下降曲线
-
未进行特征缩放
- 问题:特征尺度差异大会导致梯度下降效率低下
-
解决:对特征进行标准化 (z-score) 或归一化 (缩放到[0,1] 区间)
-
忘记添加偏置项
- 问题:模型缺少截距项,可能导致决策边界无法正确分类
-
解决:确保特征矩阵 X 的第一列全是 1
-
数据线性不可分
- 问题:逻辑回归只能学习线性决策边界
-
解决:尝试添加多项式特征或使用其他分类算法如 SVM、神经网络
-
类别不平衡
- 问题:一个类别的样本远多于另一个类别,导致模型偏向多数类
- 解决:使用过采样、欠采样或调整分类阈值
6. 进阶建议
- 正则化
- 添加 L1 或 L2 正则项防止过拟合
-
修改代价函数为:
$$ 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)}))] + \frac{\lambda}{2m}\sum_{j=1}^n\theta_j^2 $$ -
特征工程
- 尝试添加多项式特征
- 使用领域知识构造新特征
-
进行特征选择减少冗余
-
多分类扩展
- 使用一对多 (one-vs-all) 策略处理多分类问题
-
对每个类别训练一个二分类器
-
其他优化算法
- 尝试共轭梯度法、BFGS 等更高级的优化算法
- 使用 MATLAB 的
fminunc函数自动选择优化方法
7. 思考题
- 如果我们的数据不是线性可分的,应该如何修改我们的逻辑回归模型?
- 当特征维度很高 (如 1000 维) 时,逻辑回归可能会遇到什么问题?如何解决?
- 如何确定正则化参数 λ 的最佳值?
8. 总结
通过本文的完整实现,我们走过了逻辑回归从理论到实践的整个流程:从数据准备、模型实现到结果分析和可视化。MATLAB 提供了强大的矩阵运算和优化工具,使得实现机器学习算法变得相对简单。
逻辑回归作为分类问题的入门算法,虽然结构简单,但包含了机器学习中的许多核心概念,如梯度下降、概率建模、决策边界等。掌握好逻辑回归的实现,将为学习更复杂的机器学习算法打下坚实基础。
建议读者尝试修改数据集或调整参数,观察模型表现的变化,这样可以获得更直观的理解。在实际应用中,还需要考虑模型评估、特征工程等更多因素,这些内容我们将在后续文章中继续探讨。
