ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python TIL:用 collections.Counter 快速统计元素出现次数

Python TIL:用 collections.Counter 快速统计元素出现次数 文档教程知识库【免费下载链接】til:memo: Today I Learned项目地址https://gitcode.com/gh_mirrors/ti/til点击查看免费下载本篇技术笔记聚焦 Python 标准库collections模块中的Counter对象讲解如何用它简洁、高效地完成统计某类键出现次数的计数任务并以其在 Byte-Pair EncodingBPE字节对编码探索性实现中统计相邻字节对的实际案例为主线展开。读完本文你将掌握Counter的核心计数语义默认值为 0、任意整数计数、可哈希键能够在词频统计、共现矩阵、BPE 词表构建等场景中直接写出可复用的计数代码并理解它与defaultdict(int)的等价关系与各自适用边界。Counter 是什么面向计数的 dict 子类Python 的collections模块自带一个名为Counter的对象它是一个专门面向对键的计数tally这一需求设计的 dict 子类。它继承了普通字典的所有行为按键存取、迭代、len()等同时在此基础上附加了计数相关的便捷能力。其数据模型非常直观正如关联文档 python/keep-a-tally-with-collections-counter.md 所引述的官方定义它是一种集合其中元素以字典键的形式存储元素出现的次数以字典值的形式存储。计数值允许是任意整数包括零和负数。理解这句话是掌握Counter的关键键是被统计的对象可以是字符串、整数也可以是元组等任意可哈希对象下文 BPE 示例中的(int, int)元组即是一例值是出现次数默认从 0 起步允许自增到任意正整数计数不限于自然数支持零与负数这意味着它同样可以表达抵消扣减等语义配合subtract()等操作可实现多数据源的差额统计。因此Counter适合一切统计键出现多少次的问题例如词频统计、日志错误码统计、标签频次统计、字符/字节对共现统计等且无需引入任何第三方依赖。计数默认从 0 开始无需先初始化键普通字典在访问一个不存在的键时会抛出KeyError因此先检查键是否存在、再累加是初学者最常见的样板代码。Counter的底层实现通过__missing__机制为任意新键提供了默认值0这让从 0 开始累加变得理所当然。文档中给出的交互式验证直接说明了这一点 counts Counter() counts[hello] 0 counts[hello] 1 counts[hello] 1关键行为拆解Counter()构造一个空计数器访问从未出现过的键hello直接返回默认值0而不是抛出异常counts[hello] 1等价于取出当前值 0加 1写回 1首次累加即完成初始化再次访问时得到1。也就是说Counter把键是否存在的判断完全隐藏掉了你只需专注在计数逻辑本身。这正是它在计数场景下比裸dict更顺手的原因——同样的累加逻辑如果用普通字典你需要先if key not in d: d[key] 0多出一次显式判空。实战BPE 实现中统计相邻字节对计数能力的典型落地场景来自作者的一次真实实践在做 Byte-Pair EncodingBPE字节对编码的探索性实现时需要统计输入文本中每个相邻字节对adjacent pair出现的次数。BPE 是一种常见的数据压缩与分词tokenization算法其核心步骤之一就是反复找出出现频率最高的相邻字节/字符对然后将其合并为一个新符号——而这个找出最高频对的过程正依赖对相邻对的精确计数。文档中的完整实现如下from collections import Counter def get_pair_counts(token_ids: list[int]) - Counter: Count how often each adjacent pair appears counts Counter() for i in range(len(token_ids) - 1): pair (token_ids[i], token_ids[i 1]) counts[pair] 1 return counts这段代码的可取之处在于一次遍历完成全部计数从0到len(token_ids) - 2依次取相邻两项组成二元组每个二元组只统计一次元组直接充当键pair是(token_ids[i], token_ids[i 1])形式的int二元组。文档特别指出由int值组成的元组是可哈希hashable的因此它们作为Counter的键完全可行。这正是 Python 元组可哈希、列表不可哈希特性的实际应用——如果试图用列表[a, b]作为键会直接抛出TypeError: unhashable type: list返回值直接是Counter类型函数签名标注- Counter调用方可以立即使用Counter的后续能力见下一节例如通过most_common(1)找出频次最高的相邻对这正是 BPE 迭代合并的决策依据。例如对token_ids [1, 2, 1, 2, 1]调用get_pair_counts会得到Counter({(1, 2): 2, (2, 1): 2})其中(1, 2)与(2, 1)各出现两次随后即可据此选择要合并的目标对。深入 Counter计数之外的高频能力Counter的价值不止于默认值 0 自增。作为 dict 子类它自带一批计数专用的方法与运算符让统计之后的取用同样顺手。以下能力均为 Python 官方文档中Counter的标准接口取出频次最高的若干项most_common() counts Counter({a: 3, b: 1, c: 2}) counts.most_common(2) [(a, 3), (c, 2)]返回按计数降序排列的(键, 计数)列表传入参数n可只取前 n 项不传参数则返回全部元素。它是找出最高频对象这类需求如 BPE 中寻找最频繁合并对、排行榜 Top-K的直接答案。批量累加与扣减update() 与 subtract() counts Counter(a1) counts.update([a, b, b]) # 从可迭代对象累加等价于逐个 1 counts Counter({b: 2, a: 2}) other Counter(b1, c1) counts.subtract(other) # 逐项相减允许出现 0 或负数 counts Counter({a: 2, b: 1, c: -1})update()支持从可迭代对象或另一个映射累加计数subtract()则逐键做减法结果允许为 0 或负数——这也呼应了文档开头计数可以是任意整数包括零和负数的说明。计数值的加减乘除与交集并集Counter重载了算术与位运算可直接合并多份统计数据 c1 Counter(a3, b1) c2 Counter(a1, b2) c1 c2 # 对应键计数相加负数计数会被剔除 Counter({a: 4, b: 3}) c1 - c2 # 对应键计数相减只保留正数结果 Counter({b: 1}) c1 c2 # 交集每个键取两个计数中的较小值 Counter({a: 1, b: 1}) c1 | c2 # 并集每个键取两个计数中的较大值 Counter({a: 3, b: 2})展开元素与求和elements() 与 total() counts Counter(a3, b1) list(counts.elements()) [a, a, a, b]elements()按计数次数重复展开每个键计数小于等于 0 的键会被忽略total()Python 3.10 及以上版本提供则返回所有计数的总和。两者在把计数器还原成原始序列与求总样本量的场景中非常实用。与 defaultdict(int) 的关系同一种思路的两种表达Counter并非实现默认值累加的唯一方案。仓库中的姊妹篇文档 python/easy-key-value-aggregates-with-defaultdict.md 专门介绍了collections.defaultdict并给出了与本文完全等价的get_pair_counts写法from collections import defaultdict def get_pair_counts(token_ids: list[int]) - Counter: Count how often each adjacent pair appears counts defaultdict(int) for i in range(len(token_ids) - 1): pair (token_ids[i], token_ids[i 1]) counts[pair] 1 return counts两者的核心机制同源当键不存在时Counter与defaultdict(int)都会调用零值构造器int()作为__missing__的默认结果因此都无需在首次累加前手动把键初始化为 0。区别在于后续能力如果只需要累加计数并按键读取两者都够用如果需要most_common()、元素展开、计数器间加减合并等专有操作Counter开箱即用如果需要每个新键默认得到[]、0或其他自定义工厂值的通用聚合如按长度分组的defaultdict(list)defaultdict更通用。相关文档还对比了其他语言中的笨拙写法——先if key not in dict判空、再初始化空列表、最后追加——以此说明 Python 中Counter/defaultdict这类默认值聚合方案带来的代码简洁度提升。适用场景与选型建议综合以上分析可以给出如下实践建议需求推荐方案统计键出现次数并取最高频 Top-NCountermost_common()合并多份统计结果加法、交集、并集Counter的-|运算符词频统计、字符/字节对共现统计、日志分类计数Counter通用键值聚合新键默认[]、0、自定义对象defaultdict(factory)从零开始手写判空累加都不推荐Python 已有更优雅的内置方案Counter是 Python 标准库中小而美的典型它不引入任何依赖却把计数这一高频需求从三五行的样板代码压缩为一次自增同时通过 dict 子类的身份保留了所有熟悉的字典操作。无论是 BPE 这样的算法探索还是日常的数据清洗与统计它都值得成为你的默认计数工具。若想继续在仓库中寻找相关内容可在 README.md 的 Python 分类下找到本文及其姊妹篇 python/easy-key-value-aggregates-with-defaultdict.md两者共同覆盖了 Python 内置默认值聚合的两条主要路径。赞分享文档教程知识库【免费下载链接】til:memo: Today I Learned项目地址https://gitcode.com/gh_mirrors/ti/til点击查看免费下载相关推荐type-challenges 题解 09989用 CountElementNumberToObject 统计数组元素出现次数递归展开 元组长度计数type challenges 题解 09989用 CountElementNumberToObject 统计数组元素出现次数递归展开 元组长度计数示例工程新手避坑指南hackathon-starter 常见报错 FAQ 与快速解决方案新手避坑指南hackathon starter 常见报错 FAQ 与快速解决方案 Hackathon Starter 是一款开箱即用的 Node.js Web教育前端后端TypeHero Advent of TypeScript 2024 Day 18用 CountT, Item 在类型层面统计元组元素出现次数TypeHero Advent of TypeScript 2024 Day 18用 CountT, Item 在类型层面统计元组元素出现次数 本篇文章以教育前端后端上一篇XCOM 2模组管理器终极指南AML启动器完整教程下一篇Monitorian进阶指南5种智能场景让显示器管理更高效创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表