说明
《Python 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
计算几个重复的对象是编程中的一个常见问题。 Python 提供了大量工具和技术,您可以使用它们来解决这个问题。 然而,Python 的 Counter 是 collections 模块提供了一个清晰、高效和 Pythonic 的解决方案。这个字典子类提供了开箱即用的高效计数功能,作为 Python 开发人员,了解 Counter 以及如何有效地使用它是一项方便的技能。
有时您需要对给定数据的对象进行计数,以了解它们出现的频率,换句话说,您需要确定它们的重复的次数。当您的数据清单很短时,计算项目可以简单快捷。然而,当你有一个很长的数据清单时,计算事情可能更具挑战性。
要对对象进行计数,通常使用计数器,它是一个初始值为零的整数变量。然后增加计数器以反映给定对象在输入数据源中出现的次数。一个最为简单的解决方案是利用字典,将要计数的对象计在键上,将其数量计在值上,通过对计数对象的迭代进行统计,例如:
words = '我爱花花草草'
counter_dict = {}
for w in words:
if w in counter_dict:
counter_dict[w] += 1
else:
counter_dict[w] = 1
counter_dict
# {'我': 1, '爱': 1, '花': 2, '草': 2}
注意:使用 Python 字典计算多个重复对象时,请记住它们必须是可散列的,因为它们将用作字典键。可散列意味着对象的散列值必须在其生存期内永不更改。在 Python 中,不可变对象也是可散列的。
那么以上问题,可以使用 Counter 快速解决:
from collections import Counter
words = '我爱花花草草'
Counter(words)
# Counter({'我': 1, '爱': 1, '花': 2, '草': 2})
Counter 的特点:
它有几个特有方法:
elements()
:返回一个迭代器,元素为所有键组成的原数据,比如一个元素计数为 2,就会显示两个,0 或者负值的不会出现most_common([n])
:返回一个出现次数从大到小的前 n 个元素的列表,每个元素是由键值组成的元组subtract([iterable-or-mapping])
:将两个 Counter 对象中的元素对应的计数相减形成一个新的 Counter实例化一个 Counter 有以下几种方法:
from collections import Counter
# 实例化元素为空的 Counter 对象
a = Counter()
# 从可迭代对象
c = Counter('abbccc')
c = Counter(['a', 'b', 'b', 'c', 'c', 'c']+)
# 从 mapping
c = Counter({'a':1, 'b':2, 'c':3})
c = Counter({'a':1, 'b':2, 'a':2, 'c':3}) # 只保留一个 a
# 从关键词参数
c = Counter(a=1, b=2, c=3)
c
# Counter({'a': 1, 'b': 2, 'c': 3})
读取:
c
# Counter({'a': 1, 'b': 2, 'c': 3})
c['a'] # 1
c['x'] # 0
c.get('y', 120) # 120
Counter 额外支持字典中没有的三个方法:
返回一个迭代器,元素为所有键组成的原数据,比如一个元素计数为 2,就会显示两个,0 或者负值的不会出现:
from collections import Counter
c = Counter(a=1, b=2, c=3)
c
# Counter({'a': 1, 'b': 2, 'c': 3})
c.elements()
# <itertools.chain at 0x7fda9e629760>
[*c.elements()]
# ['a', 'b', 'b', 'c', 'c', 'c']
Python 官方给出了一个用它的特性来做指数乘积的应用案例:
# Knuth's example for prime factors of 1836: 2**2 * 3**3 * 17**1
>>> prime_factors = Counter({2: 2, 3: 3, 17: 1})
>>> product = 1
>>> for factor in prime_factors.elements(): # 循环因数
... product *= factor # 并将它们相乘
>>> product
1836
注意,如果元素的计数已设置为零或为负数,elements()
将忽略它。
c.most_common(n=None)
返回一个出现次数从大到小的前 m 个元素的列表,每个元素是由键值组成的元组:
c
# Counter({'a': 1, 'b': 2, 'c': 3})
c.most_common(10)
c.most_common()
# [('c', 3), ('b', 2), ('a', 1)]
c.most_common(2)
# [('c', 3), ('b', 2)]
c.most_common(0)
c.most_common(-1)
# []
n 为可选参数,通过上面的代码可以总结出:
将两个 Counter 对象中的元素对应的计数相减形成一个新的 Counter:
from collections import Counter
c1 = Counter(a=1, b=2, c=3)
c2 = Counter(a=2, b=1, c=0, d=4)
c2.subtract(c1) # 直接更新 c2
c2
# Counter({'a': 1, 'b': -1, 'c': -3, 'd': 4})
+c2 # 正值
# Counter({'a': 1, 'd': 4})
-c2 # 负值
# Counter({'b': 1, 'c': 3})
简单说就是两个 Counter 中的对应键对应计数相减,当对应的元素不存在的时候,会认为其计数为 0,上例 d 便得到结果为 4。在现有计数器上使用加号(+)作为一元运算符时,将获得计数大于零的所有对象。如果使用减号(-),则得到的对象计数为负数。请注意,结果不包括计数在这两种情况下均等于零的对象。
update() 方法工作方式与字典并不相同。update([iterable-or-mapping])
从 迭代对象 计数元素或者 从另一个 映射对象 (或计数器) 添加。 像 dict.update() 但是是加上,而不是替换。另外,迭代对象 应该是序列元素,而不是一个 (key, value) 对。
一些常用的方法:
sum(c.values()) # 所有计数的总数
c.clear() # 重置所有计数
list(c) # 列出唯一的元素
set(c) # 转换成集合
dict(c) # 转换成普通字典
c.items() # 转换为 elem, cnt) 的列表
Counter(dict(list_of_pairs)) # 从 (elem, cnt) 列表转换
c.most_common()[:-n-1:-1] # n 最小公共元素
+c # 除零和负计数
提供了几个数学操作,可以结合 Counter 对象,以生产 multisets (计数器中大于0的元素)。 加和减,结合计数器,通过加上或者减去元素的相应计数。交集和并集返回相应计数的最小或最大值。每种操作都可以接受带符号的计数,但是输出会忽略掉结果为零或者小于零的计数。
c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
c + d # 将两个计数器相加: c[x] + d[x]
# Counter({'a': 4, 'b': 3})
c - d # 减计数)
# Counter({'a': 2})
c & d # 交集 min(c[x], d[x])
# Counter({'a': 1, 'b': 1})
c | d # 合集 max(c[x], d[x])
# Counter({'a': 3, 'b': 2})
单目加和减(一元操作符)意思是从空计数器加或者减去。
c = Counter(a=2, b=-4)
+c
# Counter({'a': 2})
-c
# Counter({'b': 4})
以下案例演示了如何利用 Counter 计算元周率后几位中数字的分布情况:
from collections import Counter
import math
pi = math.pi
pi
# 3.141592653589793
Counter(str(pi).replace('.', ''))
'''
Counter({'3': 3,
'1': 2,
'4': 1,
'5': 3,
'9': 3,
'2': 1,
'6': 1,
'8': 1,
'7': 1})
'''
更新时间:Oct. 3, 2021, 12:28 p.m. 标签:python 计数