
Python机器学习对数入门
图片作者 | Midjourney
引言
对数是数学、统计学和数据科学的基石,在机器学习的各个方面都有体现。它们支撑着指数增长、p值、对数似然等基本概念。在机器学习和数据科学中,我们经常处理跨越多个数量级的数据。例如,基因表达水平、金融时间序列和人口数量的规模可能差异巨大。对数变换可以管理这些差异,揭示可能隐藏的潜在趋势。
对数用于确定必须将某个基数提高到哪个指数才能得到给定数字。形式上,对于基数 \( b > 0 \)(且 \( b \neq 1 \))
\[
\log_b(a) = x \quad \text{当且仅当} \quad b^x = a, \, (a > 0).
\]
最常见的基数是
- 以10为底(常用对数):\(\log_{10}(a)\)
- 以 \( e \) 为底(自然对数):\(\ln(a)\) 或 \(\log_e(a)\)
- 以2为底(二进制对数):\(\log_2(a)\)
在实际的数据相关工作中,**自然对数**尤其常见,特别是在连续数学和统计学中(例如,带有对数变换结果的线性回归或对数似然函数)。自然对数在数据工作中被广泛使用,因为它能将乘法关系简化为加法关系,从而更容易分析和解释指数过程和统计模型。
本教程将清晰地介绍对数、它们的性质以及它们在机器学习中的常见应用。在本教程结束时,您将了解
- 什么是对数以及它们为什么有用
- 使它们如此强大的关键性质
- 在机器学习中的应用
- 使用SymPy进行Python的简要演示
- 使用PyTorch在Python中进行对数应用的实际代码示例
对数的关键性质
对数能将乘法和指数运算简化为更易于管理的运算。一些基本的对数性质是
乘法法则
此法则指出,乘积的对数等于其各个因子的对数之和。它允许将复杂的乘法运算分解为更简单的加法任务。
\[
\log_b(xy) = \log_b(x) + \log_b(y)
\]
除法法则
根据除法法则,除法的对数是分子对数与分母对数之差。此性质简化了对数表达式中处理除法的过程。
\[
\log_b\left(\frac{x}{y}\right) = \log_b(x) – \log_b(y)
\]
幂法则
幂法则指出,指数化值的对数等于指数乘以基数值的对数。这简化了具有幂次变量的表达式的操作。
\[
\log_b(x^r) = r \, \log_b(x)
\]
换底公式
换底公式允许将对数从一个基数转换为另一个基数,从而便于计算或比较。通过用不同基数表示对数,可以使用更方便或标准化的对数表或计算器进行计算。
\[
\log_b(x) = \frac{\log_k(x)}{\log_k(b)}
\]
这些性质极大地降低了处理乘积、商和幂的复杂性。与其处理大数或难以处理的数,不如通过加减对数或乘以指数来简化。
使用SymPy进行简单的对数演示
以下是使用Python和**SymPy**库进行符号对数运算的简要演示。SymPy允许对数学表达式进行精确的运算。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import sympy as sp # 定义符号变量 x, y = sp.symbols('x y', positive=True) # 使用对数定义表达式 expr = sp.log(x) + sp.log(y) print("原始表达式:", expr) # Sympy可以将对数和简化为单个对数 simplified_expr = sp.simplify(expr) print("简化表达式:", simplified_expr) # 演示幂法则 expr_power = sp.log(x**2) print("幂表达式:", expr_power) simplified_power_expr = sp.simplify(expr_power) print("简化幂表达式:", simplified_power_expr) # 数值评估演示 # 我们定义 x=10, y=100 并评估 log(x*y) value = expr.subs({x: 10, y: 100}) print("x=10, y=100 时 log(x) + log(y) 的值:", value.evalf()) |
以上代码的解释
- 符号变量:我们将x和y声明为positive,以避免对数函数的域问题
- 表达式创建:我们创建expr = sp.log(x) + sp.log(y)
- 表达式简化:**sp.simplify(expr)** 使用对数的乘法法则将和简化为log(x*y)
- 幂法则:**sp.log(x**2)** 会被自动识别,进一步简化得到2*log(x)
- 数值评估:我们将数值代入表达式,并使用**.evalf()**评估结果
输出
1 2 3 4 5 |
原始 表达式: log(x) + log(y) 简化 表达式: log(x*y) 幂 表达式: log(x**2) 简化 幂 表达式: 2*log(x) x=10, y=100 时 log(x) + log(y) 的 值: 6.90775527898214 |
机器学习中的对数
对数在机器学习中至关重要,因为它们可以处理大数、稳定计算并简化模型中经常出现的指数关系。无论您处理的是巨大的特征值、微小的概率还是指数增长过程,对数变换可能决定了模型能否平稳收敛,还是会遇到数值溢出或下溢问题。下面,我们将重点介绍对数如此重要的主要原因,展示如何使用不同的对数底,并说明机器学习工作流程中一些常见的情况。
压缩和转换数据
机器学习经常涉及跨越多个数量级的数据——例如,图像中的像素值、文本词语计数或金融数据中的大价格范围。对数变换可以将这些宽泛的范围压缩到更易于管理的尺度。在实践中,这通常
- 减少偏斜:高度偏斜的分布变得更对称
- 强调相对变化:对数变换着重于比率,而不是绝对差异(例如,从100到200的变化比例与从10到20的变化比例相同)
对于数值特征,使用 \(\log(x+1)\)(以避免零值或负值的问题)可以帮助模型更容易地学习关系。
线性化指数关系
机器学习中的许多过程(如增长、衰减或重复乘法)本质上是指数级的。通过取对数,指数趋势就变成线性趋势,某些算法对此处理得更平稳。
- 线性回归:如果目标变量相对于特征呈指数增长,使用 \(\log(y)\) 作为目标可以稳定方差并提高模型性能
- 更简单的模式:一旦应用对数变换,乘法交互就会以加法形式出现,使模式对于假设加法关系的算法来说更清晰。
不同的底,相似的形状
虽然**以 \(e\) 为底**(自然对数)在机器学习中最为常见——尤其是在连续数学和神经网络框架中——但在特定情况下,其他底也可以发挥作用。
- 常用对数(以10为底):常用于解释性或绘制“数量级”图表
- 二进制对数(以2为底):常见于计算语境(例如,算法复杂度)或基因组学等领域,其中“倍数变化”通常是2的幂
从数学上讲,在底数之间切换很简单(\(\log_b(x) = \log_k(x) / \log_k(b)\)),因此选择底数通常取决于约定或可读性。
交叉熵损失的对数骨架
对数在交叉熵损失函数中的一个典型应用,该函数广泛用于分类任务。
\[
\text{交叉熵}(y, \hat{p}) = – \log(\hat{p}(y)),
\]
其中 \(\hat{p}(y)\) 是正确类别 \(y\) 的预测概率。在多分类场景中,这变为
\[
-\sum_{i=1}^{k} \mathbf{1}_{i=y} \cdot \log(\hat{p}_i)
\]
当模型为正确类别分配极小的概率时,取该概率的负对数会导致很大的惩罚。这会引导模型在训练过程中将概率质量转移到正确类别。大多数深度学习框架会在底层集成这种对数变换,自动将原始输出(logits)转换为概率,然后计算对数似然。
逻辑回归和对数几率
在**逻辑回归**中,对数函数用于logit(对数几率)变换。
\[
\log\bigl(\tfrac{p}{1-p}\bigr) = \mathbf{w}^\mathsf{T}\mathbf{x} + b.
\]
这种方法巧妙地将预测概率限制在 \([0, 1]\) 区间内,同时允许对数几率在所有实数范围内变化。训练依赖于最大化对数似然,这再次将乘积转换为和,并避免了极端数值。
神经网络中的数值稳定性
神经网络经常依赖**log-sum-exp**技巧来避免在处理指数时发生溢出或下溢。例如,softmax输出层计算
\[
\hat{p}_i = \frac{\exp(z_i)}{\sum_{j=1}^{k} \exp(z_j)},
\]
并且许多框架将 \(\log(\sum_j \exp(z_j))\) 重写为
\[
\alpha + \log\Bigl(\sum_j \exp(z_j – \alpha)\Bigr),
\]
其中 \(\alpha\) 是最大logit。这使得值保持在稳定的数值范围内。每当您在机器学习中看到指数或概率时,对数通常都在后台确保计算的稳健性。
PyTorch中的实际示例
下面是一个简短的代码片段,展示了PyTorch的**CrossEntropyLoss**如何在内部应用对数来进行分类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import torch import torch.nn as nn # 假设我们有一个包含3个样本和4个类别的批次 logits = torch.tensor([ [ 2.0, -1.0, 0.0, 4.0], [ 1.0, 2.0, 3.0, -1.0], [-2.0, 0.0, 2.0, 1.0] ]) # 真实标签(类别索引) labels = torch.tensor([3, 2, 2]) # CrossEntropyLoss = softmax + 负对数似然 criterion = nn.CrossEntropyLoss() loss = criterion(logits, labels) print(f"交叉熵损失: {loss.item():.4f}") # 为了演示,手动计算softmax和对数 softmax_vals = torch.softmax(logits, dim=1) correct_probs = softmax_vals[range(logits.size(0)), labels] nll = -torch.log(correct_probs) print("Softmax 概率:\n", softmax_vals) print("每个样本的负对数似然:", nll) print("平均损失:", nll.mean().item()) |
脚本的输出
1 2 3 4 5 6 7 |
交叉-熵 损失: 0.3294 Softmax 概率: tensor([[0.1166, 0.0058, 0.0158, 0.8618], [0.0889, 0.2418, 0.6572, 0.0120], [0.0120, 0.0889, 0.6572, 0.2418]]) 每个 样本的负对数似然: tensor([0.1488, 0.4197, 0.4197]) 平均 损失: 0.32939615845680237 |
关于上述脚本的几个额外要点
- Logits:原始输出,可以是任何实数
- CrossEntropyLoss:内部应用softmax,然后取正确类别概率的负对数
- 数值稳定性:PyTorch不采用天真的计算方法,而是使用优化且稳定的实现,避免了极小概率的下溢和极大指数的上溢。
结论
对数提供了一种优雅的方式来简化大规模或指数关系,使其在统计学、数据科学乃至机器学习的许多领域都至关重要。我们讨论中的一些关键要点是:
- 对数是通用的缩放技巧:无论是在输入数据转换中使用,还是集成到损失函数中,对数都能通过将乘积转换为和来简化计算。
- 它们可以处理大数值范围:对于保持神经网络和其他机器学习方法的计算稳定至关重要。
- 它们可以线性化指数过程:使模式对线性方法更易于处理,并有助于解释。
- 它们无处不在于机器学习:从基本的逻辑回归到驱动深度网络的交叉熵损失。
无论您是处理偏斜数据、稳定方差还是处理似然性,对数函数都可以将复杂的乘法模式转化为更易于处理的加法模式。通过掌握基本的对数性质,您可以明智地将其应用于您的分析——从而获得更简洁的模型、减少数值不稳定性以及更清晰的结果解释。
总之,扎实掌握对数——以及何时应用它们——可以提高许多机器学习模型的准确性和稳定性,使其成为各级从业者的基础概念。
暂无评论。