杰瑞科技汇

python counter 详解

目录

  1. 什么是 Counter
  2. 如何创建 Counter 对象?
  3. Counter 的核心功能与常用操作
    • 访问元素
    • 计数元素
    • 获取最常见的元素 (most_common())
    • 元素的增删改 (elements(), update(), subtract())
    • 算术和集合操作
  4. Counter 的实际应用场景
  5. Counter 的注意事项

什么是 Counter

Counter 是 Python 标准库 collections 模块中的一个类,它是一个 字典的子类,它的主要作用是:

python counter 详解-图1
(图片来源网络,侵删)

用于计数可哈希对象。

你可以把它想象成一个特殊的字典,它的键是你要计数的元素,值是每个元素出现的次数,与普通字典不同,Counter 的键默认值为 0,当你访问一个不存在的键时,它不会抛出 KeyError,而是返回 0。

Counter 的官方文档描述是: Counter 是一个 dict 子类,用于计数可哈希对象,它是一个集合,其中元素存储为字典键,它们的计数存储为字典值,计数可以是任何整数值,包括零或负数。


如何创建 Counter 对象?

创建 Counter 对象主要有以下几种方式:

a) 从可迭代对象创建(最常用)

你可以直接将一个列表、元组、字符串等可迭代对象传递给 Counter,它会自动统计每个元素的出现次数。

from collections import Counter
# 从列表创建
list_data = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
c1 = Counter(list_data)
print(c1)
# 输出: Counter({'apple': 3, 'banana': 2, 'orange': 1})
# 从字符串创建(每个字符都会被计数)
str_data = "hello world"
c2 = Counter(str_data)
print(c2)
# 输出: Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
# 从元组创建
tuple_data = (1, 2, 3, 2, 1, 4, 1)
c3 = Counter(tuple_data)
print(c3)
# 输出: Counter({1: 3, 2: 2, 3: 1, 4: 1})

b) 从映射(字典)创建

你可以传入一个字典,Counter 会使用字典的键和值来初始化。

from collections import Counter
# 从字典创建
dict_data = {'a': 4, 'b': 2, 'c': 1}
c4 = Counter(dict_data)
print(c4)
# 输出: Counter({'a': 4, 'b': 2, 'c': 1})

c) 使用关键字参数创建

你也可以直接通过关键字参数来创建,键是元素,值是计数。

from collections import Counter
c5 = Counter(apple=3, banana=2, orange=1)
print(c5)
# 输出: Counter({'apple': 3, 'banana': 2, 'orange': 1})

d) 创建空的 Counter

from collections import Counter
c_empty = Counter()
print(c_empty)
# 输出: Counter()

Counter 的核心功能与常用操作

a) 访问元素

Counter 继承了字典的访问方式,但它更“宽容”。

from collections import Counter
c = Counter({'apple': 3, 'banana': 2, 'orange': 1})
# 访问存在的键,返回计数值
print(c['apple'])
# 输出: 3
# 访问不存在的键,不会报错,而是返回 0
print(c['grape'])
# 输出: 0
# 如果想检查键是否存在,可以使用 in 操作符
print('apple' in c)
# 输出: True
print('grape' in c)
# 输出: False

b) 计数元素(update() 方法)

如果你想在现有 Counter 对象的基础上增加计数,可以使用 update() 方法,它接受一个可迭代对象或另一个映射对象,并将其元素计数累加到当前 Counter 中。

from collections import Counter
c = Counter({'apple': 3, 'banana': 2})
# 使用可迭代对象更新
c.update(['apple', 'orange', 'apple'])
print(c)
# 输出: Counter({'apple': 5, 'banana': 2, 'orange': 1})
# 使用另一个 Counter 更新
c_other = Counter({'banana': 3, 'grape': 1})
c.update(c_other)
print(c)
# 输出: Counter({'apple': 5, 'banana': 5, 'orange': 1, 'grape': 1})

注意: update()原地操作,会直接修改 Counter 对象,而不是返回一个新的。

c) 获取最常见的元素(most_common() 方法)

这是 Counter 最强大的功能之一。most_common(n) 返回一个包含 n 个最常见的元素及其计数的列表,已按计数从高到低排序,如果省略 n,则返回所有元素。

from collections import Counter
c = Counter('abracadabra')
print(c)
# 输出: Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
# 获取最常见的 3 个元素
print(c.most_common(3))
# 输出: [('a', 5), ('b', 2), ('r', 2)]
# 获取所有元素(已排序)
print(c.most_common())
# 输出: [('a', 5), ('b', 2), ('r', 2), ('c', 1), ('d', 1)]

d) 元素的增删改

  • 增加计数:

    • 直接通过 c[key] += 1 的方式。
    • 使用 update() 方法(推荐,可以批量增加)。
  • 减少计数:

    • 直接通过 c[key] -= 1 的方式。
    • 使用 subtract() 方法(update 的反向操作,会减少计数)。
    from collections import Counter
    c = Counter({'apple': 3, 'banana': 2})
    # 直接减少
    c['apple'] -= 1
    print(c)
    # 输出: Counter({'apple': 2, 'banana': 2})
    # 使用 subtract() 方法
    c.subtract({'apple': 1, 'banana': 3, 'orange': 1})
    print(c)
    # 输出: Counter({'apple': 1, 'banana': -1, 'orange': 1})

    注意: subtract() 允许计数变为零或负数,这是 Counter 的一个特性。

  • 删除元素:

    • 使用 del c[key] 可以完全删除一个键值对。
    • 使用 c.pop(key) 可以删除并返回该键的计数值。
    from collections import Counter
    c = Counter({'apple': 3, 'banana': 2, 'orange': 1})
    del c['orange']
    print(c)
    # 输出: Counter({'apple': 3, 'banana': 2})
    popped_value = c.pop('banana')
    print(f"Popped value: {popped_value}")
    print(c)
    # 输出:
    # Popped value: 2
    # Counter({'apple': 3})
  • 获取所有元素(elements() 方法) elements() 方法返回一个迭代器,其中元素按任意顺序重复出现,次数由其计数决定。计数小于或等于 0 的元素不会被包含。

    from collections import Counter
    c = Counter({'apple': 2, 'banana': 1, 'orange': 0, 'grape': -1})
    print(list(c.elements()))
    # 输出: ['apple', 'apple', 'banana']
    # 'orange' (0) 和 'grape' (-1) 被忽略了

e) 算术和集合操作

Counter 对象支持一些算术和集合操作,这些操作会丢弃小于等于 0 的计数。

  • 加法 ():两个 Counter 的计数相加。

    c1 = Counter(a=3, b=1)
    c2 = Counter(a=1, b=2, c=4)
    print(c1 + c2)
    # 输出: Counter({'a': 4, 'b': 3, 'c': 4})
  • 减法 ():从第一个 Counter 中减去第二个 Counter 的计数,只保留正数计数。

    c1 = Counter(a=3, b=1)
    c2 = Counter(a=1, b=2, c=4)
    print(c1 - c2)
    # 输出: Counter({'a': 2})  # b 变成了 -1, 被丢弃
  • 交集 (&):取两个 Counter 中每个元素计数的最小值

    c1 = Counter(a=3, b=2)
    c2 = Counter(a=1, b=3, c=1)
    print(c1 & c2)
    # 输出: Counter({'a': 1, 'b': 2})
  • 并集 ():取两个 Counter 中每个元素计数的最大值

    c1 = Counter(a=3, b=2)
    c2 = Counter(a=1, b=3, c=1)
    print(c1 | c2)
    # 输出: Counter({'a': 3, 'b': 3, 'c': 1})

Counter 的实际应用场景

Counter 在处理数据时非常高效,以下是几个常见场景:

统计词频

这是最经典的用法,比如分析一篇文章中每个单词出现的频率。

from collections import Counter
import re
text = """
Python is an amazing language. Python is versatile and easy to learn.
Many people love Python because of its simplicity.
"""
# 转换为小写,并提取所有单词
words = re.findall(r'\b\w+\b', text.lower())
# 使用 Counter 统计词频
word_counts = Counter(words)
# 打印最常见的5个词
print(word_counts.most_common(5))
# 输出可能为: [('python', 3), ('is', 2), ('an', 1), ('amazing', 1), ...] (具体取决于正则和文本)

查找列表中的重复项

快速找出一个列表中哪些元素是重复的,以及重复了多少次。

from collections import Counter
items = [1, 2, 3, 4, 2, 5, 1, 2, 6, 7, 8, 1]
item_counts = Counter(items)
# 找出所有出现超过1次的元素
duplicates = {item: count for item, count in item_counts.items() if count > 1}
print(duplicates)
# 输出: {1: 3, 2: 3}

比较两个列表的差异

比较两个列表,找出哪些元素在 list_a 中比在 list_b 中多。

from collections import Counter
list_a = [1, 2, 2, 3, 4, 4, 5]
list_b = [2, 3, 4, 4, 6]
counter_a = Counter(list_a)
counter_b = Counter(list_b)
# 使用减法,找出 list_a 中独有的元素及其数量
difference = counter_a - counter_b
print(difference)
# 输出: Counter({1: 1, 2: 1, 5: 1})

Counter 的注意事项

  1. 不是真正的多线程安全Counter 的操作(如 updatesubtract)是原子性的,但如果你在多线程环境中对同一个 Counter 对象进行复杂的、连续的操作(例如先检查再更新),可能会导致竞争条件,在多线程环境下,需要使用锁来保护 Counter 对象。

  2. 元素必须是可哈希的:和字典的键一样,Counter 中的元素必须是可哈希的类型(如 int, str, tuple),你不能用 listdict 作为 Counter 的键。

  3. 计数可以为零或负数:虽然 elements() 和集合操作会忽略零或负数的计数,但 Counter 对象本身可以存储这些值,这在某些特定算法(如计算差集)中是有用的。

  4. most_common() 的时间复杂度most_common() 方法的时间复杂度大约是 O(n log n),因为它内部使用了排序,如果你的 Counter 非常大,频繁调用此方法可能会影响性能。


collections.Counter 是 Python 中一个极其方便且高效的工具,它将复杂的计数任务简化为几行代码。

特性 描述
本质 dict 的子类,用于计数。
创建 可从列表、字符串、元组、字典等创建。
访问 像字典一样访问,不存在的键返回 0。
核心方法 most_common() (获取高频元素), elements() (获取所有元素), update() (增加计数), subtract() (减少计数)。
算术操作 支持 , , &, ,结果会自动过滤掉 <= 0 的计数。
适用场景 词频统计、查找重复项、数据比较、数据分析等任何需要计数的场景。

掌握 Counter 可以让你在处理计数相关的问题时事半功倍,是 Python 工具箱中不可或缺的一员。

分享:
扫描分享到社交APP
上一篇
下一篇