本文要点
Counter的构造方式不止一种,选哪种取决于你手里已经有什么
数完次数后,通常想知道出现最多的几个词
这是Counter和普通字典差别最明显的一处,也是初学者容易踩坑的地方

本文目录
先明确要解决的问题:一份自建词列表,数每个词出现几次
假设你在练习目录里准备了一份自建词列表,比如从一段自己写的文字里按空格拆出来的词,想知道每个词各出现几次。这类“计数”任务用collections.Counter最直接。
Counter是dict的子类,专门用来统计可哈希对象的出现次数。它把元素存成字典的键,把计数存成字典的值。也就是说,它长得像字典,但用途是计数。
本文只处理三件事:怎么构造Counter、怎么用most_common取出现次数最多的若干项、查询一个不存在的词会得到什么。所有示例都是自建的练习数据,不读取网页,也不涉及真实语料。
动手前建议在练习目录里新建一个脚本,例如exercise/count_demo.py,不要拿重要数据直接试。
三种构造方式:空Counter、从可迭代对象、从映射或关键字
Counter的构造方式不止一种,选哪种取决于你手里已经有什么。
第一种,先建一个空Counter,再逐个累加。适合边读边数的场景:
from collections import Counter
cnt = Counter()
for word in ["red", "blue", "red", "green", "blue", "blue"]:
cnt[word] += 1
print(cnt)这段代码里,cnt[word] += 1 能直接对还不存在的键做加法,是因为Counter对缺失项返回0,而不是抛KeyError。运行后输出形如 Counter({'blue': 3, 'red': 2, 'green': 1})。
第二种,直接把可迭代对象交给Counter,一步完成计数:
from collections import Counter
words = ["red", "blue", "red", "green", "blue", "blue"]
print(Counter(words))结果和第一种一样。列表、字符串这类可迭代对象都能这样传进去。
第三种,从一个映射或关键字参数初始化:
from collections import Counter
print(Counter({"red": 4, "blue": 2}))
print(Counter(cats=4, dogs=8))第一种写法把已有计数字典直接变成Counter,第二种用关键字参数指定元素和计数。三种方式得到的是同一种对象,后续方法都能用。
most_common怎么用:取前几名,以及不传参数时的区别
数完次数后,通常想知道出现最多的几个词。most_common就是做这件事的。
它返回一个列表,元素是(词, 次数)这样的元组,按次数从多到少排列。传入n就只返回前n项:
from collections import Counter
words = ["red", "blue", "red", "green", "blue", "blue"]
cnt = Counter(words)
print(cnt.most_common(2))按资料给出的示例形式,输出是 [('blue', 3), ('red', 2)]。
如果不传参数,或者传None,most_common()返回全部元素,同样按次数从多到少排列。
有一个细节值得记住:次数相同的元素,按它们第一次被遇到的顺序排列。所以并列第二的项谁在前,取决于它在数据里先出现的位置,不是按字母顺序。
如果你只想看最少出现的几项,资料里给出的写法是 c.most_common()[:-n-1:-1],这是对完整结果做反向切片,属于进阶用法,初学时可以先只用正序的most_common(n)。
查询不存在的项:返回0,而不是报错
这是Counter和普通字典差别最明显的一处,也是初学者容易踩坑的地方。
普通字典用方括号取一个不存在的键,会抛KeyError。Counter不会,它返回0:
from collections import Counter
c = Counter(["eggs", "ham"])
print(c["bacon"])输出是 0。
这个行为带来两个后果。
第一,你可以放心地写 cnt[word] += 1,不用先判断这个词在不在里面。第一次遇到时,它读到0,加1后变成1,键也就此建立。
第二,查询结果里的0有两种可能:这个词真的出现过0次,或者这个词根本没在数据里出现过。Counter不区分这两种情况,都返回0。如果你需要区分,可以用 in 判断键是否存在,例如 "bacon" in c。
还有一个容易误解的点:把某个计数设成0,并不会把这个键删掉。要彻底移除,得用del:
c["sausage"] = 0
del c["sausage"]第一行只是把计数写成0,键还在;第二行才真正移除这个条目。
拿自建词列表走一遍:从构造到取前三名到查缺失词
把前面几节串起来,用一份自建词列表完整走一遍。
from collections import Counter
words = ["tea", "coffee", "tea", "water", "tea", "coffee"]
cnt = Counter(words)
print(cnt)
print(cnt.most_common(2))
print(cnt["juice"])
print("juice" in cnt)按资料说明的行为,可以预期:
1. cnt 显示每个词和它的次数,tea出现3次,coffee出现2次,water出现1次。
2. most_common(2) 返回前两名,即 tea 和 coffee 及其次数。
3. cnt["juice"] 返回0,因为juice不在数据里。
4. "juice" in cnt 返回False,说明这个键确实不存在,而不是计数为0。
第3步和第4步放在一起看,就能理解为什么单看返回值0不够——它既可能是“出现过0次”,也可能是“没出现过”。
以上数值只针对这份自建列表,换一份数据结果就会不同。
检查结果时容易看错的几处
拿到计数结果后,建议按下面几点核对,避免误读。
1. 大小写和空格。Counter按元素原样计数,"Tea"和"tea"是两个不同的键。如果你的词列表来自自己拆分的文本,先确认拆分规则是否统一。
2. most_common的并列顺序。次数相同的项按首次遇到的顺序排,不要以为它按字母排。
3. 计数为0不等于键不存在。用 in 判断键是否存在,别只看返回值。
4. 计数可以是0或负数。Counter允许计数为任意整数,包括0和负数。如果你看到负数,说明数据或累加过程里有减法操作,不是Counter本身出错。
5. most_common要求值可排序。它需要计数之间能比较大小,所以计数得是能排序的类型。
这些检查都是围绕自建数据做的,不涉及对真实语料的判断。
适用限制与参考资料
本文只讲Counter的构造、most_common和查询不存在项这三件事,处理的是自建词列表。不涉及从网页抓取文本、不涉及文件读写、不涉及Counter之间的加减与集合运算。
示例中的词列表、文件名和输出都是自建的练习数据,不是对真实语料或真实项目的记录。运行前请在练习目录里操作,不要拿重要数据直接试。
关于Counter的构造方式、most_common的排序规则、缺失项返回0、以及计数为0与删除键的区别,依据是Python官方collections模块文档中Counter objects一节。文档还说明Counter自Python 3.1加入,3.7起作为dict子类会记住插入顺序。
如果你需要统计的是文件里的词,那属于读取和分词环节,本文不展开。
观看知识要点视频 18 秒
18秒无旁白要点导览,文字来自已审核正文;完整步骤、条件及参考资料见下方。
参考资料
以下原始资料提供本文依据;请结合日期、适用条件和产品说明查阅。
请结合原始资料的适用条件阅读。
返回表格与数据 →