用Python的Counter计算一个列表中每个元素的出现次数

商业

在 Python 中,一个列表或元组中所有元素的数量可以通过内置函数 len() 得到,每个元素的数量 (每个元素出现的次数) 可以通过 count() 方法得到。

此外,Python标准库中的Counter类可以用来按照出现次数的多少来获取元素。

在本节中,我们将讨论以下内容

  • 计算元素的总数。len()
  • 计算每个元素的数量(每个元素出现的次数)。count()
  • 使用方法。collections.Counter
  • 元素是按照出现的频率来检索的。most_common()
  • 计算非重叠元素(唯一元素)的数量(类型)。
  • 计算满足条件的元素的数量。

此外,作为一个具体的例子,下面用示例代码解释。

  • 计算一个词在一个字符串中的出现次数。
  • 计算一个字符串中的字符出现的次数。

这个例子是一个列表,但同样的处理也可以用图元来完成。

计算元素的总数: len()

要计算一个列表或元组中元素的总数,可以使用内置函数 len()。

l = ['a', 'a', 'a', 'a', 'b', 'c', 'c']

print(len(l))
# 7

计算每个元素的数量(每个元素出现的次数):count()方法

要计算每个元素的数量(每个元素出现的次数),请使用列表、图元等的count()方法。

如果一个不存在的元素的值被作为参数传递,则返回0。

l = ['a', 'a', 'a', 'a', 'b', 'c', 'c']

print(l.count('a'))
# 4

print(l.count('b'))
# 1

print(l.count('c'))
# 2

print(l.count('d'))
# 0

如果你想一次性获得每个元素的出现次数,下面的collection.Counter很有用。

如何使用collection.Counter

Python标准库中的集合有一个Counter类。

Counter()是字典类型dict的一个子类,它的数据形式是以元素为键,以出现的次数为值。

import collections

l = ['a', 'a', 'a', 'a', 'b', 'c', 'c']

c = collections.Counter(l)
print(c)
# Counter({'a': 4, 'c': 2, 'b': 1})

print(type(c))
# <class 'collections.Counter'>

print(issubclass(type(c), dict))
# True

如果指定了一个元素作为键,可以获得元素的数量。如果指定了一个不存在的元素的值,则返回0。

print(c['a'])
# 4

print(c['b'])
# 1

print(c['c'])
# 2

print(c['d'])
# 0

你也可以使用字典类型的方法,如keys(), values(), items()等。

print(c.keys())
# dict_keys(['a', 'b', 'c'])

print(c.values())
# dict_values([4, 1, 2])

print(c.items())
# dict_items([('a', 4), ('b', 1), ('c', 2)])

这些方法返回dict_keys类型的对象,等等。如果你想运行for语句,它们可以原样使用。如果你想把它转换为一个列表,请使用list()。

按照出现频率的顺序获取元素:most_common()方法

Counter有一个most_common()方法,它返回一个形式为(element, number of occurrences)的图元列表,按照出现的次数排序。

print(c.most_common())
# [('a', 4), ('c', 2), ('b', 1)]

可以通过指定一个索引来获得出现次数最多的元素,比如[0]表示出现次数最多的元素,[-1]表示出现次数最少的元素。如果你想只得到元素或只得到出现次数,你可以进一步指定索引。

print(c.most_common()[0])
# ('a', 4)

print(c.most_common()[-1])
# ('b', 1)

print(c.most_common()[0][0])
# a

print(c.most_common()[0][1])
# 4

如果你想按照出现次数递减的顺序排序,请使用增量设置为-1的切片。

print(c.most_common()[::-1])
# [('b', 1), ('c', 2), ('a', 4)]

如果为most_common()方法指定参数n,则只返回出现次数最多的n个元素。如果省略它,则返回所有元素。

print(c.most_common(2))
# [('a', 4), ('c', 2)]

如果你想要一个单独的按出现次数排序的元素/occurrences列表,而不是一个(元素,出现次数)的元组,你可以按以下方式分解它

values, counts = zip(*c.most_common())

print(values)
# ('a', 'c', 'b')

print(counts)
# (4, 2, 1)

内置函数zip()用于对一个二维列表(在这里是一个图元列表)进行转置,然后对其进行解包和提取。

计算非重叠元素(唯一元素)的数量(类型)。

要计算一个列表或元组中有多少个不重叠的元素(唯一的元素)(有多少种类型),可以使用上面描述的Counter或set()。

Counter对象中的元素数等于原始列表中不重叠的元素数,这可以通过len()获得。

l = ['a', 'a', 'a', 'a', 'b', 'c', 'c']
c = collections.Counter(l)

print(len(c))
# 3

你也可以使用set(),即set类型的构造函数set,如果你不需要一个Counter对象,这就更容易了。

集合类型是一种没有重复元素的数据类型。向 set() 传递一个列表会忽略重复的值,并返回一个只有唯一的值作为元素的 set 类型的对象。这种类型的元素的数量由 len() 得到。

print(set(l))
# {'a', 'c', 'b'}

print(len(set(l)))
# 3

计算满足条件的元素的数量。

要计算一个列表或元组中满足某个条件的元素的数量,可以使用列表理解符号或生成器表达式。

作为一个例子,计算以下数字列表中具有负值的元素的数量

l = list(range(-5, 6))
print(l)
# [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]

将条件表达式应用于列表理解符号中的每个元素,可以得到一个列表,其元素是布尔型的bool(真,假)。布尔类型 bool 是整数类型 int 的子类,其中 true 被视为 1,false 被视为 0。因此,真值的数量(满足条件的元素数量)可以通过使用 sum() 计算总和来计算。

print([i < 0 for i in l])
# [True, True, True, True, True, False, False, False, False, False, False]

print(sum([i < 0 for i in l]))
# 5

如果我们用()代替列表理解符号中的[],我们就会得到一个生成器表达式。列表理解符号生成一个所有被处理元素的列表,而生成器表达式是按顺序处理这些元素的,因此更节省内存。

当生成器表达式是唯一的参数时,()可以省略,所以可以写成后一种情况。

print(sum((i < 0 for i in l)))
# 5

print(sum(i < 0 for i in l))
# 5

如果你想计算假值的数量(不满足条件的元素的数量),使用not。请注意,>的优先级比not高(它首先被计算),所以下面例子中(i < 0)的括号()是不必要的。

print([not (i < 0) for i in l])
# [False, False, False, False, False, True, True, True, True, True, True]

print(sum(not (i < 0) for i in l))
# 6

当然,条件本身是可以改变的。

print(sum(i >= 0 for i in l))
# 6

以下是其他一些例子。

获取一个数字列表的奇数元素数量的例子。

print([i % 2 == 1 for i in l])
# [True, False, True, False, True, False, True, False, True, False, True]

print(sum(i % 2 == 1 for i in l))
# 6

字符串列表的条件示例。

l = ['apple', 'orange', 'banana']

print([s.endswith('e') for s in l])
# [True, True, False]

print(sum(s.endswith('e') for s in l))
# 2

items()检索一个(元素,出现次数)的元组,出现次数指定条件。

下面是一个提取有两个或更多出现的元素并计算总出现次数的例子。在这个例子中,有四个a和两个c,总共有六个。

l = ['a', 'a', 'a', 'a', 'b', 'c', 'c']
c = collections.Counter(l)

print(c.items())
# dict_items([('a', 4), ('b', 1), ('c', 2)])

print([i for i in l if c[i] >= 2])
# ['a', 'a', 'a', 'a', 'c', 'c']

print([i[1] for i in c.items() if i[1] >= 2])
# [4, 2]

print(sum(i[1] for i in c.items() if i[1] >= 2))
# 6

下面是一个提取有两个或更多出现的元素的类型并计算出现次数的例子。在这个例子中,有两个类型,a和c。

print([i[0] for i in c.items() if i[1] >= 2])
# ['a', 'c']

print([i[1] >= 2 for i in c.items()])
# [True, False, True]

print(sum(i[1] >= 2 for i in c.items()))
# 2

计算一个词在一个字符串中的出现次数。

作为一个具体的例子,我们来计算一个词在一个字符串中出现的次数。

首先,用replace()方法将不必要的逗号和句号替换为空字符串,然后删除它们。然后,使用split()方法创建一个由空格分隔的列表。

s = 'government of the people, by the people, for the people.'

s_remove = s.replace(',', '').replace('.', '')

print(s_remove)
# government of the people by the people for the people

word_list = s_remove.split()

print(word_list)
# ['government', 'of', 'the', 'people', 'by', 'the', 'people', 'for', 'the', 'people']

如果你能做一个列表,你可以得到每个词出现的次数,出现的词的类型,以及collection.Counter的most_common()来得到出现次数最多的词。

print(word_list.count('people'))
# 3

print(len(set(word_list)))
# 6

c = collections.Counter(word_list)

print(c)
# Counter({'the': 3, 'people': 3, 'government': 1, 'of': 1, 'by': 1, 'for': 1})

print(c.most_common()[0][0])
# the

以上是一个非常简单的过程,所以最好使用NLTK等库来进行更复杂的自然语言处理。

另外,在日语文本的情况下,由于没有明确的单词分隔,所以不能用split()来分割文本。例如,你可以使用Janome库来实现这一点。

计算一个字符串中的字符出现的次数。

由于字符串也是一种序列类型,它们可以与count()方法一起使用,或者作为参数传递给collection.Counter()的构造函数。

s = 'supercalifragilisticexpialidocious'

print(s.count('p'))
# 2

c = collections.Counter(s)

print(c)
# Counter({'i': 7, 's': 3, 'c': 3, 'a': 3, 'l': 3, 'u': 2, 'p': 2, 'e': 2, 'r': 2, 'o': 2, 'f': 1, 'g': 1, 't': 1, 'x': 1, 'd': 1})

检索最常出现的前5个字符的例子。

print(c.most_common(5))
# [('i', 7), ('s', 3), ('c', 3), ('a', 3), ('l', 3)]

values, counts = zip(*c.most_common(5))

print(values)
# ('i', 's', 'c', 'a', 'l')