如果列表中没有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 /代码Jedis在解决这个问题上有更好的想法。
答案 0 :(得分:6)
TL; DR :是的,返回0是唯一正确的方法。 (但见结论。)
在实际分析中(即不是复数),当考虑对数时,我们传统上假设log
的域是实数正数。我们有身份:
x = exp(log(x)), for x>0.
它可以自然地扩展到x=0
,因为右侧表达式的限制在x->0+
处被明确定义并且等于0.此外,它设置{{1}是合法的}和log(0)=-inf
(再次:仅用于真实的,不是复杂的数字)。在形式上,我们扩展了实数的集合,添加了两个元素exp(-inf)=0
,-inf
并定义了一致的算术等。(出于我们的目的,我们需要+inf
,inf + x = inf
一个真实的x,x * inf = inf
等。)
另一个身份inf + inf = inf
不那么麻烦,适用于所有实数(甚至是x = log(exp(x))
或x=-inf
)。
几何平均值
可以为非负数(可能等于零)定义几何平均数。对于两个数字+inf
,a
(它自然地推广到更多数字,所以我将仅使用两个数字),它是
b
当然,gm(a,b) = sqrt(a*b), for a,b >= 0.
。记录日志,我们得到:
gm(0,b)=0
如果log(gm(a,b)) = (log(a) + log(b))/2
或a
为零,则定义明确。 (我们可以插入b
,由于我们之前定义的扩展算法,身份仍然成立。)
<强>解释强>
毫不奇怪,几何平均数的概念来自几何,最初(在古希腊)用于严格的正数。
假设我们有一个长度为log(0) = -inf
和a
的边长方形。找到面积等于矩形区域的正方形。很容易看出,正方形的边是b
和a
的几何平均值。
现在,如果我们采用b
,那么我们就没有真正的矩形,这种几何解释会破坏。其他解释也可能出现类似的问题。我们可以通过考虑例如退化的矩形和正方形来缓解它,但它可能并不总是合理的方法。
<强>结论强>
用户(数学家,工程师,程序员)如何理解几何平均值为零的含义。如果它导致严重的结果解释问题或打破计算机程序,那么首先,几何平均值的选择可能不适合作为数学模型。
正如其他答案中已经提到的,python已经实现了无穷大。它在执行a = 0
时会引发运行时警告(除以零),但操作结果是正确的。
答案 1 :(得分: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不应导致记录的分数完全消失,尽管它仍然应该惩罚记录的分数。请参阅示例Score Aggregation Techniques in Retrieval Experimentation。
例如,您的数据和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
答案 2 :(得分:0)
你应该在python 3.5中返回-math.inf
或在旧版本中返回-float('inf')
。这是因为非常接近0的数字的对数变为负无穷大。这个浮点值保留了列表之间日志总和之间的正确不等式,例如,人们期望
sumlog([5, 4, 1, 0, 2]) < sumlog([5, 1, 4, 0.0001, 1])
如果返回负无穷大,则会保持此不等式。
答案 3 :(得分:0)
您可以尝试在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
部分之后。