失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 【Python】详解 collections.Counter

【Python】详解 collections.Counter

时间:2024-01-27 06:20:07

相关推荐

【Python】详解 collections.Counter

目录

一、绪论

二、Counter 类

2.1 创建 Counter 对象

2.2 数值访问(键-值索引)

2.3 元素删除 (键-值对删除)

2.4 update() / subtract() ——元素更新 (键-值对增减)

2.5 elements()——元素全部列出

2.6most_common()—— 元素按出现频数从大到小列出

2.7算术与集合运算

2.8 常用操作范例

一、绪论

collections 作为 Python 的内建集合模块,实现了许多十分高效的特殊容器数据类型,即除了 Python 通用内置容器: dict、list、set 和 tuple 等的替代方案。在IDLE 输入 help(collections) 可查看帮助文档,其中常见的类/函数如下:

而本文详述的对象为 hashable 对象计数器 —— Counter 。

二、Counter 类

Counter,顾名思义是一个计数器。Counter 类作为一个无序的容器类型,以字典的 key-value 对形式存储元素,旨在统计各元素 (哈希项) 出现的次数。具体而言,key 表示元素,value 表示各元素 key 出现的次数,可为任意整数 (即包括0与负数)。Counter 类有时被称为bags 或 multisets 。我们在 IDLE 通过 help(collections.Counter) 可查看帮助文档。

在 Python 3.7 版更新后,作为 dict的子类,Counter 继承了记住插入顺序的功能。Counter 对象进行数学运算时同样会保持顺序。 结果会先按每个元素在运算符左边的出现时间排序,然后再按其在运算符右边的出现时间排序。

2.1 创建 Counter 对象

实例化 Counter 的常见方式为:

## 导入 Counter 类>>> from collections import Counter # class collections.Counter([iterable-or-mapping])>>> hashmap1 = Counter() # a new, empty counter>>> hashmap1Counter()## 通过可迭代对象、映射和关键字参数等实例化 Counter 对象>>> hashmap2 = Counter('happy') # a new counter from an iterable>>> hashmap2Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})>>> hashmap3 = Counter(['A', 'A', 'K', 4, 7, 7]) # a new counter from an iterable>>> hashmap3Counter({'A': 2, 'K': 1, 4: 1, 7: 2})>>> hashmap4 = Counter(('M', 'M', 4, 'A', 1, 1)) # a new counter from an iterable>>> hashmap4Counter({'M': 2, 4: 1, 'A': 1, 1: 2})>>> hashmap5 = Counter({'x':1, 'y':2}) # a new counter from a mapping>>> hashmap5Counter({'y': 2, 'x': 1})>>> hashmap6 = Counter(kangkang=1, daming=2, sam=3) # a new counter from keyword args>>> hashmap6Counter({'sam': 3, 'daming': 2, 'kangkang': 1})# 类型检查>>> type(hashmap1), type(hashmap2), type(hashmap3), type(hashmap4), type(hashmap5), type(hashmap6)(<class 'collections.Counter'>, <class 'collections.Counter'>, <class 'collections.Counter'>, <class 'collections.Counter'>, <class 'collections.Counter'>), <class 'collections.Counter'>)

可见元素从一个iterable被计数或从其他的mapping(or counter) 实现初始化。

2.2 数值访问(键-值索引)

Counter 对象类似于 dict 接口,也通过 key 索引访问 value,但注意返回的 value 表示的是 key 的计数值:

>>> hashmap2['p'] # hashmap2 = Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})2>>> hashmap3['A'] # hashmap3 = Counter({'A': 2, 'K': 1, 4: 1, 7: 2})2>>> hashmap4['M'] # hashmap4 = Counter({'M': 2, 4: 1, 'A': 1, 1: 2})2>>> hashmap5['x'] # hashmap5 = Counter({'y': 2, 'x': 1})1

而当访问的 key 不存在时,返回 0 而非 KeyError:

# count of a missing element is zero>>> hashmap2[6] # hashmap2 = Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})0>>> hashmap3[6] # hashmap3 = Counter({'A': 2, 7: 2, 'K': 1, 4: 1})0>>> hashmap4[6] # hashmap4 = Counter({'M': 2, 1: 2, 4: 1, 'A': 1})0>>> hashmap5[6] # hashmap5 = Counter({'y': 2, 'x': 1})0

作为 dict 的子类,通过 Counter.keys()、Counter.values()、Counter.items() 访问键-值对仍然适用:

# 以 hashmap2 为例>>> hashmap2 = Counter('happy')>>> hashmap2 Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})>>> hashmap2.keys()dict_keys(['h', 'a', 'p', 'y'])>>> type(hashmap2.keys())<class 'dict_keys'>>>> hashmap2.values()dict_values([1, 1, 2, 1])>>> type(hashmap2.values())<class 'dict_values'>>>> hashmap2.items()dict_items([('h', 1), ('a', 1), ('p', 2), ('y', 1)])>>> type(hashmap2.items())<class 'dict_items'>

注意,原地操作如 hashmap[key] += 1,值类型只支持加和减,故分数、小数、十进制甚至负值都适用。

2.3 元素删除 (键-值对删除)

对于 Counter 对象的元素删除应使用内置函数 del,而令 value=0 是不能删除元素(键-值对)的。

# 以 hashmap2 为例>>> hashmap2 = Counter('happy')>>> hashmap2 Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})>>> hashmap2['y'] = 0>>> hashmap2Counter({'p': 2, 'h': 1, 'a': 1, 'y': 0}) # 'y' 还在, 只是 value=0 而已>>> del hashmap2['y']>>> hashmap2Counter({'p': 2, 'h': 1, 'a': 1}) # 'y' 被删除了

2.4 update() / subtract() ——元素更新 (键-值对增减)

可以使用另外的iterable 对象或 Counter 对象实现对原 Counter 对象的元素更新 (键-值对增减)。

其中,元素增加使用 Counter.update(iterable-or-mapping) 方法:

## 以 hashmap2 为例, 其余同理>>> hashmap2 = Counter('happy')>>> hashmap2 Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})## 用 iterable 对象更新>>> hashmap2.update('hp') # 用 string 更新 (iterable 对象)>>> hashmap2Counter({'p': 3, 'h': 2, 'a': 1, 'y': 1}) >>> hashmap2.update(['a','y']) # 用 list 更新 (iterable 对象)>>> hashmap2Counter({'p': 3, 'h': 2, 'a': 2, 'y': 2})>>> hashmap2.update(('a')) # 用 tuple 更新 (iterable 对象)>>> hashmap2Counter({'a': 3, 'p': 3, 'h': 2, 'y': 2})## 用 mapping 对象更新>>> hashmap2.update({'h':1, 'y':1}) # 用 dict 更新 (mapping 对象)>>> hashmap2Counter({'h': 3, 'a': 3, 'p': 3, 'y': 3})## 用 Counter 对象更新>>> hashmap2.update(Counter('hapy'))>>> hashmap2Counter({'h': 4, 'a': 4, 'p': 4, 'y': 4})

注意,元素的添加来自 iterable 对象计数元素,或另一个 mapping 对象(或 Counter 对象) ,其中 iterable 对象应为序列 sequence 元素。

同理,元素减少使用 Counter.subtract(iterable-or-mapping) 方法,但注意元素的计数 —— value 为 0 和 负数都是允许的:

# 以 hashmap2 为例, 其余同理>>> hashmap2 = Counter('happy')>>> hashmap2 Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})# 用 iterable 对象更新元素>>> hashmap2.subtract('p') # 用 string 更新>>> hashmap2Counter({'h': 1, 'a': 1, 'p': 1, 'y': 1}) >>> hashmap2.subtract(['p']) # 用 list 更新>>> hashmap2Counter({'h': 1, 'a': 1, 'p': 0, 'y': 1}) # 允许 value <= 0>>> hashmap2.subtract(('p')) # 用 tuple 更新>>> hashmap2Counter({'h': 1, 'a': 1, 'y': 1, 'p': -1}) # 允许 value <= 0## 用 mapping 对象更新>>> hashmap2.subtract({'h':2}) # 用 dict 更新>>> hashmap2Counter({'a': 1, 'y': 1, 'h': -1, 'p': -1}) # 允许 value <= 0## 用 Counter 对象更新>>> hashmap2.update(Counter('ay'))>>> hashmap2Counter({'a': 0, 'y': 0, 'h': -1, 'p': -1})

可见使用 iterable 对象更新原 Counter 对象之前,都会被隐式地转换为 Counter 对象,再把元素更新到原 Counter 对象上。

2.5 elements()——元素全部列出

Counter.elements() 方法将返回一个迭代器。元素的计数有多少,在该迭代器中就包含多少个该元素。元素排列无确定顺序元素按首次出现的顺序返回,且不含 value<= 0 的元素。

>>> hashmap7 = Counter('happy')>>> hashmap7Counter({'p': 2, 'h': 1, 'a': 1, 'y': 1})>>> hashmap7.elements()# 返回迭代器<itertools.chain object at 0x00000249719226A0>>>> list(hashmap7.elements()) # 显式类型转换['h', 'a', 'p', 'p', 'y']>>> tuple(hashmap7.elements()) # 显式类型转换('h', 'a', 'p', 'p', 'y')>>> str(hashmap7.elements())# 那是不可能的...'<itertools.chain object at 0x0000024971125390>'>>> sorted(hashmap7.elements()) # 隐式类型转换['a', 'h', 'p', 'p', 'y']

2.6most_common()—— 元素按出现频数从大到小列出

Counter.most_common([n]) 方法将返回一个 list,其中包含前n个出现频数最高的元素及其出现次数,并从大到小排列。 若n被省略或为 None,most_common() 将返回 Counter 对象中的所有元素。若元素计数值相等,则按首次出现的顺序排序:

>>> hashmap8 = Counter(x=3, y=2, z=1, h=2)>>> hashmap8Counter({'x': 3, 'y': 2, 'h': 2, 'z': 1})>>> hashmap8.most_common(1) # n=1[('x', 3)]>>> hashmap8.most_common(2) # n=2[('x', 3), ('y', 2)]>>> hashmap8.most_common(3) # n=3[('x', 3), ('y', 2), ('h', 2)]>>> hashmap8.most_common(4) # n=4[('x', 3), ('y', 2), ('h', 2), ('z', 1)] # 'y' 与 'h' 出现频次均为 2, 但 'y' 先出现, 故前排>>> hashmap8.most_common() # n ignored[('x', 3), ('y', 2), ('h', 2), ('z', 1)] # 全排:从大到小>>> hashmap8.most_common()[::-1] # n ignored[('z', 1), ('h', 2), ('y', 2), ('x', 3)] # 全排:从小到大

2.7算术与集合运算

有几个常用的数学运算操作:

>>> h1 = Counter(x=1, y=2)>>> h2 = Counter(x=2, y=1)>>> h3 = Counter(x=1, y=-1)>>> h1 + h2Counter({'x': 3, 'y': 3}) # 按元素相加>>> h2 + h3Counter({'x': 3}) # value <= 0 的会被删除>>> h1 - h2Counter({'y': 1}) # 按元素相减>>> h1 - h3Counter({'y': 3}) # value <= 0 的会被删除>>> h1 & h2Counter({'x': 1, 'y': 1}) # 按元素取 min() (交集)>>> h1 | h2Counter({'x': 2, 'y': 2}) # 按元素取 max() (并集)

还有单目加和减 (一元操作符) 及其等价形式:

>>> hashmap9 = Counter(a=2, b=1, c=0, d=-1)>>> +hashmap9Counter({'a': 2, 'b': 1}) # 去除 value<=0 的元素>>> -hashmap9Counter({'d': 1}) # 去除 value>=0 的元素>>> hashmap9 += Counter() >>> hashmap9Counter({'a': 2, 'b': 1}) # 去除 value<=0 的元素

2.8 常用操作范例

>>> hashmap8 = Counter(x=3, y=2, z=1, h=2)>>> hashmap8Counter({'x': 3, 'y': 2, 'h': 2, 'z': 1})## 对 Counter 对象的 value 求和>>> sum(hashmap8.values()) 8## 从小到大排序>>> hashmap8.most_common()[::-1][('z', 1), ('h', 2), ('y', 2), ('x', 3)] ## 类型转换>>> list(hashmap8)['x', 'y', 'z', 'h'] # 将 Counter 对象的 key 转换为 list>>> tuple(hashmap8)('x', 'y', 'z', 'h') # 将 Counter 对象的 key 转换为 tuple>>> set(hashmap8){'z', 'y', 'x', 'h'} # 将 Counter 对象的 key 转换为 set>>> dict(hashmap8){'x': 3, 'y': 2, 'z': 1, 'h': 2} # 将 Counter 对象的转换为 dict## 去除 value <= 0 的元素>>> hashmap9 = Counter(a=2, b=1, c=0, d=-1)>>> hashmap9Counter({'a': 2, 'b': 1, 'c': 0, 'd': -1})>>> hashmap9 += Counter() >>> hashmap9Counter({'a': 2, 'b': 1})

参考文献

《Python Immediate》

collections --- 容器数据类型 — Python 3.10.4 文档

collections - 廖雪峰的官方网站

如果觉得《【Python】详解 collections.Counter》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。