机器学习:逻辑回归
简介
在前两篇文章中,我们详细探讨了如何利用采样数据来估计回归曲线。接下来,在本节中,我们将深入讨论如何处理分类问题。
章节安排
- 背景介绍
- 数学方法
- 程序实现
背景介绍
线性可分
线性可分是指在多维空间
在二分类问题中,如果数据集是线性可分的,那么可以找到一个超平面,使得屏幕的一侧的所有点属于一个类别,而另一侧的所有点都属于另一个类别。
设数据集
如果存在一个超平面
则称该数据集
在一些情形下,并不是严格线性可分的,也就是说不存在一个超平面能够将所有不同类别的点完全分隔开来。这种情况下,我们可能会考虑使用“宽松的线性可分”(Soft Margin)的概念。
在宽松线性可分中,定义松弛变量
注意到,对于任何一个超平面
,总是存在一个足够大的松弛变量 使得该超平面满足宽松线性可分条件。
因此,一般认为,对于某一个超平面,使得其满足宽松线性条件的最小常数 越小,则说明该直线划分效果越好。
初识激活函数
超平面
Sigmoid函数是一个经典的激活函数,因其连续性和较低的计算复杂度而在机器学习中得到了广泛的应用。Sigmoid 函数的定义如下:
主要特点
-
连续性和可导性:
Sigmoid 函数及其导数都是连续的,这使得它非常适合用于基于梯度下降的优化算法。 -
输出范围:
Sigmoid 函数的输出范围是 ((0, 1)),这使其在二分类问题中特别有用。它可以将线性组合的输出转换为一个概率值,从而更容易解释模型的预测结果。 -
计算复杂度:
Sigmoid 函数的计算相对简单,不涉及复杂的数学运算,这有助于提高模型的训练速度。同时,其导函数可以方便的从原函数计算,即:
逻辑回归
逻辑回归(Logistic Regression)是一种广泛应用于分类问题的统计模型和机器学习算法。尽管名称中包含“回归”,但它实际上主要用于解决分类问题,特别是二分类问题。
工作原理
-
线性组合:
首先,逻辑回归模型对输入特征进行线性组合,也称对输入进行评估: -
Sigmoid变换:
然后,将评估的结果 通过Sigmoid函数进行变换:Sigmoid函数的输出
可以解释为样本属于正类的概率。 -
决策边界:
通常,选择一个阈值(例如 )来决定分类结果:
损失函数
逻辑回归的损失函数通常采用对数损失(Log Loss)或称交叉熵损失(Cross-Entropy Loss):
其中,
优化
本文将介绍如何采用梯度下降法优化逻辑回归模型。
在梯度下降法中,核心的部分是计算损失
通常采用链式法则计算梯度,以参数
梯度下降法中,采用梯度的反方向作为更新方向,其公式为:
其中,
程序实现
在上一篇文章《机器学习:线性回归(下)》中已经讲述了超平面
激活函数
下述函数用于计算输入矩阵或向量的每个元素的Sigmoid函数值。
MatrixXd Sigmoid::cal(const MatrixXd& input) { return input.unaryExpr([](double x) { return 1.0 / (1.0 + exp(-x)); }); }
这段代码是一个简短的函数实现,代码解释如下:
-
input.unaryExpr
:
unaryExpr
是Eigen库中的一个函数,用于对矩阵或向量的每个元素应用一个给定的单变量函数。在这里,input
是一个Eigen矩阵或向量。 -
Lambda函数:
[](double x) { return 1.0 / (1.0 + exp(-x)); }
是一个Lambda函数,它定义了一个匿名函数,接受一个double
类型的参数x
,并返回1.0 / (1.0 + exp(-x))
。这个函数实现了Sigmoid函数的计算。
MatrixXd Sigmoid::grad(const MatrixXd& input) { Matrix temp = input.unaryExpr([](double x) { return 1.0 / (1.0 + exp(-x)); }); return temp.cwiseProduct((1 - temp.array()).matrix()); }
这段代码实现了激活函数的梯度的计算,类似与Sigmoid::cal()
,先计算激活函数cwiseProduct
计算(即Hadamard乘积)
对数损失
下述函数分别采用Eigen
的矩阵计算方法,实现了对数损失及对数损失的梯度的计算
double LogisticLoss::computeLoss(const MatrixXd& predicted, const MatrixXd& actual) { MatrixXd log_predicted = predicted.unaryExpr([](double p) { return log(p); }); MatrixXd log_1_minus_predicted = predicted.unaryExpr([](double p) { return log(1 - p); }); MatrixXd term1 = actual.cwiseProduct(log_predicted); // MatrixXd term2 = (1 - actual).cwiseProduct(log_1_minus_predicted); MatrixXd term2 = (1 - actual.array()).matrix().cwiseProduct(log_1_minus_predicted); double loss = -(term1 + term2).mean(); return loss; } MatrixXd LogisticLoss::computeGradient(const MatrixXd& predicted, const MatrixXd& actual) { MatrixXd temp1 = predicted - actual; MatrixXd temp2 = predicted.cwiseProduct((1 - predicted.array()).matrix()); return (temp1).cwiseQuotient(temp2); }
为了便于读者理解、学习,下面给出了LogisticLoss::computeLoss()
函数的标量方法实现(采用矩阵索引):
double computeLoss(const MatrixXd& predicted, const MatrixXd& actual) { int n = predicted.rows(); double loss = 0.0; for (int i = 0; i < n; ++i) { double p = predicted(i, 0); double y = actual(i, 0); loss += -(y * log(p) + (1 - y) * log(1 - p)); } return loss / n; }
本文来自博客园,作者:SXWisON,转载请注明原文链接:https://www.cnblogs.com/SXWisON/p/18581725
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~