解决列表中项目的产品中的零

Resolving Zeros in Product of items in list

鉴于如果列表中没有 0,我们可以轻松地在列表中的项目乘积与列表中项目的对数和之间进行转换,例如:

>>> from operator import mul
>>> pn = [0.4, 0.3, 0.2, 0.1]
>>> math.pow(reduce(mul, pn, 1), 1./len(pn))
0.22133638394006433
>>> math.exp(sum(0.25 * math.log(p) for p in pn))
0.22133638394006436

我们应该如何处理列表中和 Python 中有 0 的情况(以编程和数学上正确的方式)?

更具体地说,我们应该如何处理以下情况:

>>> pn = [0.4, 0.3, 0, 0]
>>> math.pow(reduce(mul, pn, 1), 1./len(pn))
0.0
>>> math.exp(sum(1./len(pn) * math.log(p) for p in pn))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <genexpr>
ValueError: math domain error

returning 0 真的是处理这个问题的正确方法吗? 什么是优雅的解决方案,我们考虑列表中的 0 但不是以0 秒?

因为它是某种几何平均值(列表的乘积)并且当我们 return 0 时它并不完全有用,因为列表中只有一个 0。

从 Math Stackexchange 溢出: https://math.stackexchange.com/questions/1727497/resolving-zeros-in-product-of-items-in-list,没有数学家的回答,也许 python/code Jedis 在解决这个问题上有更好的想法。

你应该 return -math.inf 在 python 3.5 或 -float('inf') 在旧版本中。这是因为非常接近 0 的数字的对数趋于负无穷大。这个浮点值保留了列表之间对数总和之间的正确不等式,例如人们会期望

sumlog([5, 4, 1, 0, 2]) < sumlog([5, 1, 4, 0.0001, 1])

如果 return 负无穷大,则此不等式成立。

您可以尝试在 Python 中使用列表解析。它们可以非常强大地定制您的数据处理方式。此示例使用列表理解和错误编号 -999

>>> [math.log(i) if i > 0 else -999 for i in pn]
>>> [-0.916290731874155, -1.2039728043259361, -999, -999]

如果您只使用 if 而不是 else,则 if 位于 for i in pn 部分之后。

TL;DR: 是的,返回0是唯一正确的方法。 (但请参阅结论。)

数学背景

在实数分析中(即不是复数),当考虑对数时,我们传统上假设 log 的域是正实数。我们有身份:

x = exp(log(x)),   for x>0.

它可以自然地扩展为x=0,因为右侧表达式的极限在x->0+处明确定义并且等于0。此外,设置log(0)=-inf是合法的和 exp(-inf)=0(同样:仅适用于实数,而非复数)。形式上,我们扩展实数集,添加两个元素 -inf+inf 并定义一致算法等。(为了我们的目的,我们需要 inf + x = infx * inf = inf一个真正的 x,inf + inf = inf 等)

另一个恒等式 x = log(exp(x)) 不那么麻烦并且适用于所有实数(甚至 x=-inf+inf)。

几何平均数

可以为非负数(可能等于零)定义几何平均值。对于两个数字 ab(它自然地推广到更多数字,所以我将只使用两个),它是

gm(a,b) = sqrt(a*b),   for a,b >= 0.

当然,gm(0,b)=0。记录下来,我们得到:

log(gm(a,b)) = (log(a) + log(b))/2

如果 ab 为零,则定义明确。 (我们可以插入 log(0) = -inf,由于我们之前定义的扩展算法,恒等式仍然成立。)

解读

毫不奇怪,几何平均数的概念源自几何学,最初(在古希腊)用于严格的正数。

假设,我们有一个边长为 ab 的矩形。找一个面积等于长方形面积的正方形。容易看出,正方形的边是ab的几何平均数。

现在,如果我们采用 a = 0,那么我们实际上并没有矩形,这种几何解释就失效了。其他解释也会出现类似的问题。例如,我们可以通过考虑退化的矩形和正方形来减轻它,但这可能并不总是一种合理的方法。

结论

这取决于用户(数学家、工程师、程序员)如何理解几何平均值为零的含义。如果它导致结果解释出现严重问题或破坏计算机程序,那么首先,几何平均数的选择可能作为数学模型是不合理的。


Python

正如其他答案中已经提到的,python 实现了无穷大。它在执行 np.exp(np.log(0)) 但操作结果正确时引发运行时警告(被零除)。

0 是否 正确 结果取决于您要完成的任务。 ptrj 的回答做得很好,所以我只会添加一件事来考虑。

您可能需要考虑使用 epsilon 调整的几何平均值。标准几何平均值的形式为 (a_1*a_2*...*a_n)^(1/n),而经 epsilon 调整的几何平均值的形式为 ( (a_1+e)*(a_2+e)*...*(a_n+e) )^(1/n) - e。 epsilon (e) 的适当值再次取决于您的任务。

Epsilon 调整的几何平均值有时用于数据检索,其中集合中的 0 不应导致记录的分数完全消失,但它仍应惩罚记录的分数。例如参见 [​​=16=].

例如,使用您的数据和 0.01

的 epsilon 调整
>>> from operator import mul
>>> pn=[0.4, 0.3, 0, 0]
>>> e=0.01
>>> pow(reduce(mul, [x+e for x in pn], 1), 1./len(pn)) - e
0.04970853116594962