Python中Collections模块的Counter容器类使用教程

1.collections模块

collections模块自Python 2.4版本开始被引入,包含了dict、set、list、tuple以外的一些特殊的容器类型,分别是:

OrderedDict类:排序字典,是字典的子类。引入自2.7。
namedtuple()函数:命名元组,是一个工厂函数。引入自2.6。
Counter类:为hashable对象计数,是字典的子类。引入自2.7。
deque:双向队列。引入自2.4。
defaultdict:使用工厂函数创建字典,使不用考虑缺失的字典键。引入自2.5。
文档参见:http://docs.python.org/2/library/collections.html。

2.Counter类

Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。Counter类和其他语言的bags或multisets很相似。

2.1 创建

下面的代码说明了Counter类创建的四种方法:

Counter类的创建Python

>>> c = Counter() # 创建一个空的Counter类
>>> c = Counter('gallahad') # 从一个可iterable对象(list、tuple、dict、字符串等)创建
>>> c = Counter({'a': 4, 'b': 2}) # 从一个字典对象创建
>>> c = Counter(a=4, b=2) # 从一组键值对创建

>>> c = Counter() # 创建一个空的Counter类
>>> c = Counter('gallahad') # 从一个可iterable对象(list、tuple、dict、字符串等)创建
>>> c = Counter({'a': 4, 'b': 2}) # 从一个字典对象创建
>>> c = Counter(a=4, b=2) # 从一组键值对创建

2.2 计数值的访问与缺失的键

当所访问的键不存在时,返回0,而不是KeyError;否则返回它的计数。

计数值的访问Python

>>> c = Counter("abcdefgab")
>>> c["a"]
2
>>> c["c"]
1
>>> c["h"]
0

>>> c = Counter("abcdefgab")
>>> c["a"]
2
>>> c["c"]
1
>>> c["h"]
0

2.3 计数器的更新(update和subtract)

可以使用一个iterable对象或者另一个Counter对象来更新键值。

计数器的更新包括增加和减少两种。其中,增加使用update()方法:

计数器的更新(update)Python

>>> c = Counter('which')
>>> c.update('witch') # 使用另一个iterable对象更新
>>> c['h']
3
>>> d = Counter('watch')
>>> c.update(d) # 使用另一个Counter对象更新
>>> c['h']
4

>>> c = Counter('which')
>>> c.update('witch') # 使用另一个iterable对象更新
>>> c['h']
3
>>> d = Counter('watch')
>>> c.update(d) # 使用另一个Counter对象更新
>>> c['h']
4

减少则使用subtract()方法:

计数器的更新(subtract)Python

>>> c = Counter('which')
>>> c.subtract('witch') # 使用另一个iterable对象更新
>>> c['h']
1
>>> d = Counter('watch')
>>> c.subtract(d) # 使用另一个Counter对象更新
>>> c['a']
-1

>>> c = Counter('which')
>>> c.subtract('witch') # 使用另一个iterable对象更新
>>> c['h']
1
>>> d = Counter('watch')
>>> c.subtract(d) # 使用另一个Counter对象更新
>>> c['a']
-1

2.4 键的删除

当计数值为0时,并不意味着元素被删除,删除元素应当使用del。

键的删除Python

>>> c = Counter("abcdcba")
>>> c
Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})
>>> c["b"] = 0
>>> c
Counter({'a': 2, 'c': 2, 'd': 1, 'b': 0})
>>> del c["a"]
>>> c
Counter({'c': 2, 'b': 2, 'd': 1})

>>> c = Counter("abcdcba")
>>> c
Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})
>>> c["b"] = 0
>>> c
Counter({'a': 2, 'c': 2, 'd': 1, 'b': 0})
>>> del c["a"]
>>> c
Counter({'c': 2, 'b': 2, 'd': 1})

2.5 elements()

返回一个迭代器。元素被重复了多少次,在该迭代器中就包含多少个该元素。所有元素按照字母序排序,个数小于1的元素不被包含。

elements()方法Python

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> list(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> list(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']

2.6 most_common([n])

返回一个TopN列表。如果n没有被指定,则返回所有元素。当多个元素计数值相同时,按照字母序排列。

most_common()方法Python

>>> c = Counter('abracadabra')
>>> c.most_common()
[('a', 5), ('r', 2), ('b', 2), ('c', 1), ('d', 1)]
>>> c.most_common(3)
[('a', 5), ('r', 2), ('b', 2)]

>>> c = Counter('abracadabra')
>>> c.most_common()
[('a', 5), ('r', 2), ('b', 2), ('c', 1), ('d', 1)]
>>> c.most_common(3)
[('a', 5), ('r', 2), ('b', 2)]

2.7 fromkeys

未实现的类方法。

2.8 浅拷贝copy

浅拷贝copyPython

>>> c = Counter("abcdcba")
>>> c
Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})
>>> d = c.copy()
>>> d
Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})

>>> c = Counter("abcdcba")
>>> c
Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})
>>> d = c.copy()
>>> d
Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})

2.9 算术和集合操作

+、-、&、|操作也可以用于Counter。其中&和|操作分别返回两个Counter对象各元素的最小值和最大值。需要注意的是,得到的Counter对象将删除小于1的元素。

Counter对象的算术和集合操作Python

>>> 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 # subtract(只保留正数计数的元素)
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=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d # c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d # subtract(只保留正数计数的元素)
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})

3.常用操作

下面是一些Counter类的常用操作,来源于Python官方文档

Counter类常用操作Python

sum(c.values()) # 所有计数的总数
c.clear() # 重置Counter对象,注意不是删除
list(c) # 将c中的键转为列表
set(c) # 将c中的键转为set
dict(c) # 将c中的键值对转为字典
c.items() # 转为(elem, cnt)格式的列表
Counter(dict(list_of_pairs)) # 从(elem, cnt)格式的列表转换为Counter类对象
c.most_common()[:-n:-1] # 取出计数最少的n个元素
c += Counter() # 移除0和负值

sum(c.values()) # 所有计数的总数
c.clear() # 重置Counter对象,注意不是删除
list(c) # 将c中的键转为列表
set(c) # 将c中的键转为set
dict(c) # 将c中的键值对转为字典
c.items() # 转为(elem, cnt)格式的列表
Counter(dict(list_of_pairs)) # 从(elem, cnt)格式的列表转换为Counter类对象
c.most_common()[:-n:-1] # 取出计数最少的n个元素
c += Counter() # 移除0和负值

4.实例
4.1判断两个字符串是否由相同的字母集合调换顺序而成的(anagram)

def is_anagram(word1, word2):
  """Checks whether the words are anagrams.

  word1: string
  word2: string

  returns: boolean
  """

  return Counter(word1) == Counter(word2)

Counter如果传入的参数是字符串,就会统计字符串中每个字符出现的次数,如果两个字符串由相同的字母集合颠倒顺序而成,则它们Counter的结果应该是一样的。

4.2多元集合(MultiSets)
multiset是相同元素可以出现多次的集合,Counter可以非常自然地用来表示multiset。并且可以将Counter扩展,使之拥有set的一些操作如is_subset。

class Multiset(Counter):
  """A multiset is a set where elements can appear more than once."""

  def is_subset(self, other):
    """Checks whether self is a subset of other.

    other: Multiset

    returns: boolean
    """
    for char, count in self.items():
      if other[char] < count:
        return False
    return True

  # map the <= operator to is_subset
  __le__ = is_subset

4.3概率质量函数
概率质量函数(probability mass function,简写为pmf)是离散随机变量在各特定取值上的概率。可以利用Counter表示概率质量函数。

class Pmf(Counter):
  """A Counter with probabilities."""

  def normalize(self):
    """Normalizes the PMF so the probabilities add to 1."""
    total = float(sum(self.values()))
    for key in self:
      self[key] /= total

  def __add__(self, other):
    """Adds two distributions.

    The result is the distribution of sums of values from the
    two distributions.

    other: Pmf

    returns: new Pmf
    """
    pmf = Pmf()
    for key1, prob1 in self.items():
      for key2, prob2 in other.items():
        pmf[key1 + key2] += prob1 * prob2
    return pmf

  def __hash__(self):
    """Returns an integer hash value."""
    return id(self)

  def __eq__(self, other):
    return self is other

  def render(self):
    """Returns values and their probabilities, suitable for plotting."""
    return zip(*sorted(self.items()))

normalize: 归一化随机变量出现的概率,使它们之和为1
add: 返回的是两个随机变量分布两两组合之和的新的概率质量函数
render: 返回按值排序的(value, probability)的组合对,方便画图的时候使用
下面以骰子(ps: 这个竟然念tou子。。。)作为例子。

d6 = Pmf([1,2,3,4,5,6])
d6.normalize()
d6.name = 'one die'
print(d6)
Pmf({1: 0.16666666666666666, 2: 0.16666666666666666, 3: 0.16666666666666666, 4: 0.16666666666666666, 5: 0.16666666666666666, 6: 0.16666666666666666})

使用add,我们可以计算出两个骰子和的分布:

d6_twice = d6 + d6
d6_twice.name = 'two dices'

for key, prob in d6_twice.items():
  print(key, prob)

借助numpy.sum,我们可以直接计算三个骰子和的分布:

import numpy as np
d6_thrice = np.sum([d6]*3)
d6_thrice.name = 'three dices'

最后可以使用render返回结果,利用matplotlib把结果画图表示出来:

for die in [d6, d6_twice, d6_thrice]:
  xs, ys = die.render()
  pyplot.plot(xs, ys, label=die.name, linewidth=3, alpha=0.5)

pyplot.xlabel('Total')
pyplot.ylabel('Probability')
pyplot.legend()
pyplot.show()

结果如下:

4.4贝叶斯统计
我们继续用掷骰子的例子来说明用Counter如何实现贝叶斯统计。现在假设,一个盒子中有5种不同的骰子,分别是:4面、6面、8面、12面和20面的。假设我们随机从盒子中取出一个骰子,投出的骰子的点数为6。那么,取得那5个不同骰子的概率分别是多少?
(1)首先,我们需要生成每个骰子的概率质量函数:

def make_die(num_sides):
  die = Pmf(range(1, num_sides+1))
  die.name = 'd%d' % num_sides
  die.normalize()
  return die

dice = [make_die(x) for x in [4, 6, 8, 12, 20]]
print(dice)

(2)接下来,定义一个抽象类Suite。Suite是一个概率质量函数表示了一组假设(hypotheses)及其概率分布。Suite类包含一个bayesian_update函数,用来基于新的数据来更新假设(hypotheses)的概率。

class Suite(Pmf):
  """Map from hypothesis to probability."""

  def bayesian_update(self, data):
    """Performs a Bayesian update.

    Note: called bayesian_update to avoid overriding dict.update

    data: result of a die roll
    """
    for hypo in self:
      like = self.likelihood(data, hypo)
      self[hypo] *= like

    self.normalize()

其中的likelihood函数由各个类继承后,自己实现不同的计算方法。

(3)定义DiceSuite类,它继承了类Suite。

class DiceSuite(Suite):

  def likelihood(self, data, hypo):
    """Computes the likelihood of the data under the hypothesis.

    data: result of a die roll
    hypo: Die object
    """
    return hypo[data]

并且实现了likelihood函数,其中传入的两个参数为: data: 观察到的骰子掷出的点数,如本例中的6 hypo: 可能掷出的那个骰子

(4)将第一步创建的dice传给DiceSuite,然后根据给定的值,就可以得出相应的结果。

dice_suite = DiceSuite(dice)

dice_suite.bayesian_update(6)

for die, prob in sorted(dice_suite.items()):
  print die.name, prob

d4 0.0
d6 0.392156862745
d8 0.294117647059
d12 0.196078431373
d20 0.117647058824

正如,我们所期望的4个面的骰子的概率为0(因为4个面的点数只可能为0~4),而6个面的和8个面的概率最大。 现在,假设我们又掷了一次骰子,这次出现的点数是8,重新计算概率:

dice_suite.bayesian_update(8)

for die, prob in sorted(dice_suite.items()):
  print die.name, prob

d4 0.0
d6 0.0
d8 0.623268698061
d12 0.277008310249
d20 0.0997229916898

现在可以看到6个面的骰子也被排除了。8个面的骰子是最有可能的。
以上的几个例子,展示了Counter的用处。实际中,Counter的使用还比较少,如果能够恰当的使用起来将会带来非常多的方便。

(0)

相关推荐

  • 简介Python的collections模块中defaultdict类型的用法

    defaultdict 主要用来需要对 value 做初始化的情形.对于字典来说,key 必须是 hashable,immutable,unique 的数据,而 value 可以是任意的数据类型.如果 value 是 list,dict 等数据类型,在使用之前必须初始化为空,有些情况需要把 value 初始化为特殊值,比如 0 或者 ''. from collections import defaultdict person_by_age = defaultdict(list) for pers

  • Python的collections模块中的OrderedDict有序字典

    如同这个数据结构的名称所说的那样,它记录了每个键值对添加的顺序. d = OrderedDict() d['a'] = 1 d['b'] = 10 d['c'] = 8 for letter in d: print letter 输出: a b c 如果初始化的时候同时传入多个参数,它们的顺序是随机的,不会按照位置顺序存储. >>> d = OrderedDict(a=1, b=2, c=3) OrderedDict([('a', 1), ('c', 3), ('b', 2)]) 除了和

  • 详解Python的collections模块中的deque双端队列结构

    deque 是 double-ended queue的缩写,类似于 list,不过提供了在两端插入和删除的操作. appendleft 在列表左侧插入 popleft 弹出列表左侧的值 extendleft 在左侧扩展 例如: queue = deque() # append values to wait for processing queue.appendleft("first") queue.appendleft("second") queue.appendl

  • Python标准库之collections包的使用教程

    前言 Python为我们提供了4种基本的数据结构:list, tuple, dict, set,但是在处理数据量较大的情形的时候,这4种数据结构就明显过于单一了,比如list作为数组在某些情形插入的效率会比较低,有时候我们也需要维护一个有序的dict.所以这个时候我们就要用到Python标准库为我们提供的collections包了,它提供了多个有用的集合类,熟练掌握这些集合类,不仅可以让我们让写出的代码更加Pythonic,也可以提高我们程序的运行效率. defaultdict defaultd

  • 简单掌握Python的Collections模块中counter结构的用法

    counter 是一种特殊的字典,主要方便用来计数,key 是要计数的 item,value 保存的是个数. from collections import Counter >>> c = Counter('hello,world') Counter({'l': 3, 'o': 2, 'e': 1, 'd': 1, 'h': 1, ',': 1, 'r': 1, 'w': 1}) 初始化可以传入三种类型的参数:字典,其他 iterable 的数据类型,还有命名的参数对. | __init

  • Python的collections模块中namedtuple结构使用示例

    namedtuple 就是命名的 tuple,比较像 C 语言中 struct.一般情况下的 tuple 是 (item1, item2, item3,...),所有的 item 都只能按照 index 访问,没有明确的称呼,而 namedtuple 就是事先把这些 item 命名,以后可以方便访问. from collections import namedtuple # 初始化需要两个参数,第一个是 name,第二个参数是所有 item 名字的列表. coordinate = namedtu

  • 使用Python的内建模块collections的教程

    collections是Python内建的一个集合模块,提供了许多有用的集合类. namedtuple 我们知道tuple可以表示不变集合,例如,一个点的二维坐标就可以表示成: >>> p = (1, 2) 但是,看到(1, 2),很难看出这个tuple是用来表示一个坐标的. 定义一个class又小题大做了,这时,namedtuple就派上了用场: >>> from collections import namedtuple >>> Point = n

  • Python collections模块实例讲解

    collections模块基本介绍 我们都知道,Python拥有一些内置的数据类型,比如str, int, list, tuple, dict等, collections模块在这些内置数据类型的基础上,提供了几个额外的数据类型: 1.namedtuple(): 生成可以使用名字来访问元素内容的tuple子类2.deque: 双端队列,可以快速的从另外一侧追加和推出对象3.Counter: 计数器,主要用来计数4.OrderedDict: 有序字典5.defaultdict: 带有默认值的字典 n

  • Python中Collections模块的Counter容器类使用教程

    1.collections模块 collections模块自Python 2.4版本开始被引入,包含了dict.set.list.tuple以外的一些特殊的容器类型,分别是: OrderedDict类:排序字典,是字典的子类.引入自2.7. namedtuple()函数:命名元组,是一个工厂函数.引入自2.6. Counter类:为hashable对象计数,是字典的子类.引入自2.7. deque:双向队列.引入自2.4. defaultdict:使用工厂函数创建字典,使不用考虑缺失的字典键.引

  • Python中optionParser模块的使用方法实例教程

    本文以实例形式较为详尽的讲述了Python中optionParser模块的使用方法,对于深入学习Python有很好的借鉴价值.分享给大家供大家参考之用.具体分析如下: 一般来说,Python中有两个内建的模块用于处理命令行参数: 一个是 getopt,<Deep in python>一书中也有提到,只能简单处理 命令行参数: 另一个是 optparse,它功能强大,而且易于使用,可以方便地生成标准的.符合Unix/Posix 规范的命令行说明. 示例如下: from optparse impo

  • Python中collections模块的基本使用教程

    前言 之前认识了python基本的数据类型和数据结构,现在认识一个高级的:Collections,一个模块主要用来干嘛,有哪些类可以使用,看__init__.py就知道 '''This module implements specialized container datatypes providing alternatives to Python's general purpose built-in containers, dict, list, set, and tuple. * named

  • Python中collections.Counter()的具体使用

    目录 Counter类 创建 计数值的访问与缺失的键 计数器的更新 键的删除 elements() most_common([n]) fromkeys 浅拷贝copy 算术和集合操作 常用操作 Counter类 Counter类的目的是用来跟踪值出现的次数.它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value.计数值可以是任意的Interger(包括0和负数).Counter类和其他语言的bags或multisets很相似. 创建 Counter是一个容器对象

  • Python的collections模块真的很好用

    collections是实现了特定目标的容器,以提供Python标准内建容器 dict , list , set , 和 tuple 的替代选择.为了让大家更好的认识,本文详细总结collections的相关知识,一起来学习吧! collections模块:实现了特定目标的容器,以提供Python标准内建容器 dict.list.set.tuple 的替代选择. Counter:字典的子类,提供了可哈希对象的计数功能. defaultdict:字典的子类,提供了一个工厂函数,为字典查询提供了默认

  • Python中itertools模块用法详解

    本文实例讲述了Python中itertools模块用法,分享给大家供大家参考.具体分析如下: 一般来说,itertools模块包含创建有效迭代器的函数,可以用各种方式对数据进行循环操作,此模块中的所有函数返回的迭代器都可以与for循环语句以及其他包含迭代器(如生成器和生成器表达式)的函数联合使用. chain(iter1, iter2, ..., iterN): 给出一组迭代器(iter1, iter2, ..., iterN),此函数创建一个新迭代器来将所有的迭代器链接起来,返回的迭代器从it

  • 详解Python中Addict模块的使用方法

    目录 介绍 1.安装 2.用法 3.要牢记的事情 4.属性,如键.item等 5.默认值 6.转化为普通字典 7.计数 8.更新 9.Addict 是怎么来的 介绍 Addit 是一个Python模块,除了提供标准的字典语法外,Addit 生成的字典的值既可以使用属性来获取,也可以使用属性进行设置. 这意味着你不用再写这样的字典了: body = {     'query': {         'filtered': {             'query': {              

  • Python中typing模块的具体使用

    目录 typing库 一. 简介 二. 别名 1. 类型别名 2. NewType 3. 可调用对象 三. 泛型支持 1.集合类型 2. 抽象基类 3. 泛型 4. Any 5. 特殊形式 5.1 Type 5.2 Union 5.3 Optional 5.4 Tuple 5.5 Callable typing库 一. 简介 Python是一门弱类型的语言,很多时候我们可能不清楚函数参数类型或者返回值类型,很有可能导致一些类型没有指定方法,在写完代码一段时间后回过头看代码,很可能忘记了自己写的函

  • python中pygame模块用法实例

    本文实例讲述了python中pygame模块用法,分享给大家供大家参考.具体方法如下: import pygame, sys from pygame.locals import * #set up pygame pygame.init() windowSurface = pygame.display.set_mode((500, 400), 0, 32) pygame.display.set_caption("hello, world") BLACK = (0, 0, 0) WHITE

  • python中string模块各属性以及函数的用法介绍

    任何语言都离不开字符,那就会涉及对字符的操作,尤其是脚本语言更是频繁,不管是生产环境还是面试考验都要面对字符串的操作. python的字符串操作通过2部分的方法函数基本上就可以解决所有的字符串操作需求: • python的字符串属性函数 • python的string模块 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1.字符串属性函数  系统版本:CentOS release 6.2 (Final)2.6.32-220.

随机推荐