如何在Python语言中重现以下概率函数?



我有一个任务,我有一个特定值的列表:l = ["alpha", "beta", "beta", "alpha", "gamma", "alpha", "alpha"]。在这个列表中,我有一个计算某种概率的公式,如下所示(如果列表中有许多不同的值,则概率高,如果有几种值,则概率低):

$ p = - sum_{i=1}^m f_i log_m f_i $

其中m为链表的长度,$f_i$为链表第i个元素出现的频率。

我想用以下代码在Python中编写:

from math import log
from collections import Counter
-sum([loc*log(loc, len(set(l))) for loc in Counter(l).values()])

但我怀疑这不是正确的方式。有更好的主意吗?另外:我看不懂公式中的负号,怎么解释?

这里有另一种方法来计算列表使用numpy:

import numpy as np
arr = np.array(l)
elem, c = np.unique(arr, return_counts=True)
# occurrences to probabilities
pc = c / c.sum()
# calculate the entropy (and account for log_m)
entropy = -np.sum(pc * np.log(pc)) * (1/np.log(len(c)))

虽然numpy数组是一个更好的解决方案,但如果您不想使用numpy:

  1. 如果您保存计数器并使用len(counter)而不是len(set(l)),那么您将更好,这样您就不会在每次迭代中重新计算in。len(Counter)与len(set(l))相同,但不会在每次迭代中重新计算(我假设您使用cpython3。x)
  2. 如果你没有得到想要的结果,那么可能你的公式是错误的
  3. 在你的代码中,你使用len(set(l))而不是len(l),你迭代频率,而不是你在公式中描述的列表。
  4. 你不需要将表达式包装在列表中的sum中,因为你只需要迭代它一次(生成器表达式与列表推导式)

编辑:至于为什么你得到一个否定的结果,这是预期的对f[i] * log(f[i])>= 0求和

  • f[i]>= 1:列表中第i个元素出现的频率
  • log(f[i])>= 0,因为f[i]>= 1:每个频率在任意基(基无关)的对数。

然后取它的负值。结果总是小于或等于0。

from math import log
from collections import Counter
l = ["alpha", "beta", "beta", "alpha", "gamma", "alpha", "alpha"]
f = Counter(l)
# This is from your code
p1 = -sum(f[e] * log(f[e], len(f)) for e in f)
# This is from your formula
p2 = -sum(f[e] * log(f[e], len(l)) for e in l)
print(p1, p2)

最新更新