
本文介绍使用defaultdict嵌套counter结构,高效统计分词标注文本中每个单词的总出现次数及其对应各词性(pos)标签的频次分布,并输出结构化结果。
本文介绍使用defaultdict嵌套counter结构,高效统计分词标注文本中每个单词的总出现次数及其对应各词性(pos)标签的频次分布,并输出结构化结果。
在自然语言处理的预处理阶段,常需解析形如 word/POS 的标注文本(如Penn Treebank格式),并统计每个单词的全局频次及它在不同词性标签下的分布情况。例如,动词“reported”可能同时标注为过去分词 VBN(7次)和过去式 VBD(9次),需合并呈现。
最简洁高效的方案是采用 collections.defaultdict(Counter):外层 defaultdict 自动为每个新单词初始化一个 Counter 对象,内层 Counter 则专门负责该单词下各POS标签的计数。相比手动检查键存在性或嵌套字典,此结构既避免 KeyError,又天然支持累加与聚合操作。
以下是完整可运行示例:
from collections import defaultdict, Counter
input_filename = "pos_tagged.txt"
wordcounts = defaultdict(Counter)
with open(input_filename, "r") as f:
for line in f:
line = line.strip()
if not line: # 跳过空行
continue
try:
word, pos = line.rsplit('/', 1) # 仅从右侧分割一次,兼容含斜杠的词(如 "U.S./NNP")
wordcounts[word][pos] += 1
except ValueError:
continue # 忽略格式异常行(如无 '/' 的脏数据)
# 输出:单词、总频次、POS标签及对应频次(按出现顺序排列)
for word, pos_counter in wordcounts.items():
total = pos_counter.total() # Python 3.10+;旧版本可用 sum(pos_counter.values())
pos_parts = [f"{pos} {count}" for pos, count in pos_counter.items()]
print(f"{word}\t{total}\t{' '.join(pos_parts)}")
关键注意事项:
- 使用
line.strip()预处理每行,消除换行符与首尾空格,防止rsplit失败; -
rsplit('/', 1)确保只分割最右侧的/,避免误切含斜杠的单词(如"U.S./NNP"); -
Counter.total()在 Python ≥3.10 可用;若使用旧版本,请替换为sum(pos_counter.values()); - 输出字段间建议用制表符
\t分隔,便于后续导入Excel或pandas;如需固定列宽对齐,可用str.ljust()或format()控制; - 若需按总频次降序排列,可在循环前添加:
for word, pos_counter in sorted(wordcounts.items(), key=lambda x: -x[1].total()):。
该方法时间复杂度为 O(n),空间利用率高,代码简洁且具备良好可扩展性——如后续需增加词形归一化(lemma)或上下文特征,只需在 word 键生成逻辑处扩展即可。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











