【问题标题】:How to normalize a Counter and combine 2 normalized Counters? - python如何规范化一个计数器并组合 2 个规范化的计数器? - Python
【发布时间】:2014-03-15 19:43:39
【问题描述】:

首先,我有两个字符串列表:

['abc','abc','def','jkl']
['abc','def','def','pqr', 'pr', 'foo', 'bar']

然后我需要标准化列表的计数器,使每个计数器中的值之和等于 1:

Counter({'abc': 0.8164965809277261, 'jkl': 0.4082482904638631, 'def': 0.4082482904638631})
Counter({'abc': 1.1498299142610595, 'def': 1.0749149571305296, 'jkl': 0.4082482904638631, 'pr': 0.3333333333333333, 'bar': 0.3333333333333333, 'pqr': 0.3333333333333333, 'foo': 0.3333333333333333})

归一化因子是

math.sqrt(sum(i*i for i in counter.values()))

我通过迭代 throw counter 键尝试了以下操作,但是还有其他方法可以实现 say x+y Counter 吗?

>>> from collections import Counter
>>> import math
>>> x = Counter(['abc','abc','def','jkl'])
>>> denominator = 1/math.sqrt(sum(math.pow(i,2) for i in x.values()))
>>> for i in x:
...     x[i]*=denominator
... 
>>> x
Counter({'abc': 0.8164965809277261, 'jkl': 0.4082482904638631, 'def': 0.4082482904638631})
>>> y = Counter(['abc','def','def','pqr', 'pr', 'foo', 'bar'])
>>> denominator2 = 1/math.sqrt(sum(math.pow(i,2) for i in y.values()))
>>> for i in y:
...     y[i]*=denominator2
... 
>>> y
Counter({'def': 0.6666666666666666, 'pr': 0.3333333333333333, 'abc': 0.3333333333333333, 'bar': 0.3333333333333333, 'pqr': 0.3333333333333333, 'foo': 0.3333333333333333})
>>> x+y
Counter({'abc': 1.1498299142610595, 'def': 1.0749149571305296, 'jkl': 0.4082482904638631, 'pr': 0.3333333333333333, 'bar': 0.3333333333333333, 'pqr': 0.3333333333333333, 'foo': 0.3333333333333333})

【问题讨论】:

    标签: python list counter


    【解决方案1】:

    您需要对这些值求和,然后将每个计数除以总和:

    total = sum(x.values(), 0.0)
    for key in x:
        x[key] /= total
    

    通过以0.0 开始求和,我们确保total 是一个浮点值,避免了/ 使用整数操作数的Python 2 地板除法行为。

    演示:

    >>> from collections import Counter
    >>> x = Counter(['abc','abc','def','jkl'])
    >>> total = sum(x.values(), 0.0)
    >>> for key in x:
    ...     x[key] /= total
    ... 
    >>> x
    Counter({'abc': 0.5, 'jkl': 0.25, 'def': 0.25})
    >>> y = Counter(['abc','def','def','pqr', 'pr', 'foo', 'bar'])
    >>> total = sum(y.values(), 0.0)
    >>> for key in y:
    ...     y[key] /= total
    ... 
    >>> y
    Counter({'def': 0.2857142857142857, 'pr': 0.14285714285714285, 'abc': 0.14285714285714285, 'bar': 0.14285714285714285, 'pqr': 0.14285714285714285, 'foo': 0.14285714285714285})
    

    如果您需要对计数器求和,则需要单独重新规范化生成的计数器;例如,将两个归一化计数器相加意味着您有一个新的计数器整数值总和为 2。

    【讨论】:

    • 感谢 @martijn 的快速回答,但我有一个错字,应该先 sum 然后 sqrt 否则 sqrt(pow(i,2)) == i ;P
    • @alvas: 那么答案是:不,没有办法在所有键上使用/*。只定义了加法和减法。
    • 用推导式替换 for 循环更快:{k:v/total for k,v in x.iteritems()}。这将返回一个普通的旧dict。但是使用这种方法转换回Counter 仍然更快:Counter({k:v/total for k,v in x.iteritems()})。还有@MartijnPieters 不错的提示,在sum 中使用浮动品脱起始值。
    【解决方案2】:

    List 对象 (l1) 的 Counter 对象 (c1) 的规范化是将每个计数除以列表中作为列表长度 (total) 的总元素。与计算 (c1) 中的总计数(如 sum(c1.values(), 0.0))相比,这成本更低。

    可以使用给出的第一个列表中的以下示例:

    l1 = ['abc','abc','def','jkl']
    c1 = Counter(l1)
    # Normalization
    total = 1.0 * len(l1) # converting to float to avoid floor division in Python 2.X
    for k in c1:
        c1[k] /= total
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-18
      • 2016-06-04
      • 2016-05-16
      • 2021-12-13
      • 2015-04-19
      • 2011-11-20
      • 1970-01-01
      • 2015-06-10
      相关资源
      最近更新 更多