Python中的collections模块(一) 使用Counter,pythonic的对象计数方式

前言

Python 内置模块collections, 目标是提供各种专门的集合数据类型来解决特定的编程问题。

本系列介绍其中的数据结构特点和使用方法,  以便遇到某些特定的问题,可以找到对应的数据来处理, 达到事半功倍的效果

namedtuple用于创建其子类的工厂函数tuple,提供命名字段,允许按名称访问项目,同时保持按索引访问项目的能力
deque一个类似序列的集合,支持从序列的任一端有效地添加和删除项目
OrderedDict根据插入键的时间保持键值对排序的字典子类
ChainMap一个类似字典的类,允许将多个映射视为单个字典对象
⭐defaultdict一个字典子类,用于为缺失的键构建默认值并自动将它们添加到字典中
⭐Counter一个字典子类,支持方便地对序列或可迭代中的唯一项进行计数

本文介绍其中两个 defaultdict,  Counter, 其他的可以参考

Python中的collections模块(二) 有序字典OrderedDict和链接字典ChainMap

Python中的collections模块(三) 命名元组namedtuple和双端队列deque

Python中的collections模块(四) UserString,UserList,和UserDict

1.使用Python计数

工作中一个常见的场景,你需要统计一个数据中某些元素出现的次数。最常见的方法就是,便利目标数据,然后使用一个字典来存储元素和其出现次数的对应关系。

In [1]: tar = 'abcedabcdabcaba'
In [2]: counter = {}

In [3]: for letter in tar:
   ...:     if letter not in counter:
   ...:         counter[letter] = 1
   ...:     else:
   ...:         counter[letter] += 1
   
In [4]: counter
Out[4]: {'a': 5, 'b': 4, 'c': 3, 'e': 1, 'd': 2}

 遍历每一个字符都要判断一下,该字符是否已经在counter中存在,比较麻烦。

一个比较优雅的方式是使用dict.get方法,遇到不存在的key不会抛出异常,并返回一个默认值。

另一个方式是使用collections.defaultdict方法,为counter字典设置默认值。

实现代码如下:

In [8]: tar = 'abcedabcdabcaba'
In [9]: counter = {}

In [10]: for letter in tar:
    ...:     counter[letter] = counter.get(letter, 0) + 1

In [11]: counter
Out[11]: {'a': 5, 'b': 4, 'c': 3, 'e': 1, 'd': 2}
In [18]: from collections import defaultdict

In [19]: tar = 'abcedabcdabcaba'
In [20]: counter = defaultdict(int)

In [21]: for letter in tar:
    ...:     counter[letter] += 1

In [22]: counter
Out[22]: defaultdict(int, {'a': 5, 'b': 4, 'c': 3, 'e': 1, 'd': 2})

使用defaultdict 解决方案更简洁易读。首先初始花counter使用 int函数作为默认工厂函数对defaultdict进行初始化。这样,当访问不存在的键时,defaultdict字典会自动创建该键并使用工厂函数返回的值对其进行初始化。即返回0

不论上述那种方式,都需要手动对目标数据进行遍历,那么有没有不需要手动遍历数据即可获取元素计数的方法呢? 答案是有的,与编程中的许多其他常见任务一样,Python 提供了一种更好的方法来解决计数问题, 那就是Counter,在collections模块中。

2. 入门Counter

Counter是dict的一个子类,通常使用一个序列或可迭代对象作为类构造函数的参数。

将对象中每一个元素作为key,出现的次数作为value

In [22]: from collections import Counter

In [23]: tar = 'abcedabcdabcaba'

In [24]: Counter(tar)
Out[24]: Counter({'a': 5, 'b': 4, 'c': 3, 'e': 1, 'd': 2})

# list作为参数
In [25]: l = ['aa', 'abc', 'bb', 'cc', 'abc', 'abc', 'bb', 'bb']

In [26]: Counter(l)
Out[26]: Counter({'aa': 1, 'abc': 3, 'bb': 3, 'cc': 1})

2.1 更新Counter中的数据

生成一个Counter 实例后,可以通过.update()新的对象和计数来更新它, 虽然Counter是dict的一个子类,但是重写了update的功能。不是单纯的覆盖,二十将新的值和老的值相加,例子如下:

In [27]: c = Counter(tar)

In [28]: c
Out[28]: Counter({'a': 5, 'b': 4, 'c': 3, 'e': 1, 'd': 2})

# 更新Counter计数
In [29]: c.update('eeedddmmm')
In [30]: c
Out[30]: Counter({'a': 5, 'b': 4, 'c': 3, 'e': 4, 'd': 8, 'm': 6})

# 使用字典更新Counter计数
In [33]: c.update({'a':10, 'm': -5})
In [34]: c
Out[34]: Counter({'a': 15, 'b': 4, 'c': 3, 'e': 4, 'd': 8, 'm': 1})

2.2 访问Counter中的数据 

因为Counter是dict的子类,可以使用字典访问元素的方法。另外Counter还提供了一个most_common方法,将Counter实例中的元素按照出现次数排序,返回一个列表。代码示例如下

In [36]: c
Out[36]: Counter({'a': 15, 'b': 4, 'c': 3, 'e': 4, 'd': 8, 'm': 1})

# 访问和赋值其中一个元素
In [37]: c['a']
Out[37]: 15
In [38]: c['c'] = 100

# 像dict一样使用keys values和 items方法
In [40]: c.keys()
Out[40]: dict_keys(['a', 'b', 'c', 'e', 'd', 'm'])
In [41]: c.values()
Out[41]: dict_values([15, 4, 100, 4, 8, 1])
In [42]: c.items()
Out[42]: dict_items([('a', 15), ('b', 4), ('c', 100), ('e', 4), ('d', 8), ('m', 1)])

most_common方法 

In [44]: c.most_common()
Out[44]: [('c', 100), ('a', 15), ('d', 8), ('b', 4), ('e', 4), ('m', 1)]

In [45]: c.most_common(2)
Out[45]: [('c', 100), ('a', 15)]

# 按照出现次数倒序
In [46]: c.most_common()[::-1]
Out[46]: [('m', 1), ('e', 4), ('b', 4), ('d', 8), ('a', 15), ('c', 100)]

 2.3 访问Counter对象的原始数据

Counter还提供了一个.elements方法, 返回一个迭代器,用以访问被计数的对象本身。代码:

In [47]: c
Out[47]: Counter({'a': 6, 'b': 4, 'c': 4, 'e': 4, 'd': 8, 'm': 1})

In [48]: print(list(c.elements()))
['a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'e', 'e', 'e', 'e', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'm']

3. 总结

本文介绍了,python中collections.Counter 类,可以更加优雅的处理需要计数的编码场景。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值