5

鉴于如果列表中没有 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

返回 0 真的是处理这个问题的正确方法吗?什么是优雅的解决方案,让我们考虑列表中的 0 但最终不为 0?

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

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

4

4 回答 4

6

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

数学背景

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

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

它可以自然地扩展到,x=0因为右手边表达式的极限被很好地定义为x->0+等于 0。此外,设置log(0)=-infand是合法的exp(-inf)=0(同样:仅适用于实数,而不是复数)。形式上,我们扩展实数集添加两个元素-inf+inf并定义一致的算术等。(为了我们的目的,我们需要有inf + x = inf,x * inf = inf用于实数 xinf + 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

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

解释

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

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

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

结论

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


Python

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

于 2016-04-08T19:14:52.883 回答
2

结果是否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 不应导致记录的分数完全消失,尽管它仍应惩罚记录的分数。例如,参见检索实验中的分数聚合技术

例如,使用您的数据和 epsilon 调整0.01

>>> 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
于 2016-04-14T18:18:19.990 回答
0

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

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

如果您返回负无穷大,则此不等式成立。

于 2016-04-05T02:41:13.277 回答
0

您可以尝试在 Python 中使用列表推导。它们对于自定义数据处理方式非常强大。此示例使用列表推导和错误编号-999.

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

如果您只使用 theif而不是 the else,那么 theif将在该for i in pn部分之后。

于 2016-04-05T02:45:50.407 回答