利用Python统计哈姆雷特等文档中人物或词汇出现次数的方法
前言

之前我碰到了一份篇幅极长的文档,需要对该文档中特定人物或某些词汇出现的频次进行统计,单靠人力显然难以胜任。然而,我们可以借助 Python 来实现这一目标。比如,我们可以用 Python 来分析《哈姆雷特》或《红楼梦》中人物出现的频率。
首先用《哈姆雷特》试一下:
第一步:下载《哈姆雷特》英文版 TXT 文件
哈姆雷特英文版TXT文档下载:
第二步:开始编写代码
txt变量通过调用open函数以只读模式成功打开了名为"hamlet.txt"的文件,并读取了其内容。
1.对打开后的文件进行预处理
在遍历字符序列时,针对字符'ch',若其值为井号、美元符号、百分号、与号、括号、星号、加号、逗号、减号、点号、冒号或分号,则执行禁止操作。< = > ? @ [\\] ^ {}':
txt变量中的字符ch将被替换为空,以消除文本中的特定符号。
2.文本分词
txt变量中的文本内容被转换成了全部的小写字母形式。
txt内容通过split()函数被分割,若未指定分隔符,则默认以空格作为分隔依据。
这是英文的文本内容,其中的单词间自带有空格分隔,因此无需进行分词处理。这个过程可以视作文本的前期处理步骤。然而,对于中文文本,由于词与词之间并无空格分隔,因此必须借助中文分词工具来进行处理。常见的这类工具包括jieba、pkuseg、pynlpir以及thulac等。
3.词频统计
这就引出一个问题,我们对于这些词汇的预处理工作已经全部完成,但接下来它们究竟该被送往何方呢?
因此,我们需寻觅一个用于储存词汇的载体——正是所说的字典。鉴于我们旨在计算的为词汇及其出现频次,这相当于在字典中观察键与值之间的对应关系。
所以,先定义一个存放词的空字典:
counts = {}
然后我们需要把预处理过的词都放入空字典。然后计算就可以了。
if word in counts:
对单词[word]的计数进行累加,其值更新为原计数加一。
else:
counts[word] = 1
通过这种方式,我们便能够统计出每个词出现的频次,然而,这样的表达略显繁复,我们还可以采用以下更为简洁的方式来表述:
for word in words:
对单词“word”的计数进行更新,若“word”在字典中不存在,则将其初始值设为0,然后加1。
词频统计会计算所有词汇出现的频次,然而,在进行某些分析或其他需求时,我们并不需要这么详尽的词汇信息,因此,我们可以对代码进行优化和改进。
不允许使用的词汇集合包括:"the"、"and"、"of"、"you"、"a"、"i"、"my"以及"in"。
for word in excludes:
del(counts[word])
通过这种方式,我们成功剔除了诸如冠词、连接词以及一些不必要的介词等词汇。我们依旧采用for循环来逐一扫描文件中的每一个词,随后运用del函数将它们逐一移除。
排词库能够根据程序运行的过程逐步扩充词汇,从而实现输出对用户有价值的输出结果。
实际上,仅统计词汇出现次数的任务已经完成,然而,为了获取这些数据,我们需将这些信息保存下来,因此,我们设定了一个空白的列表用以存放这些结果。
items = list(counts.items())
print(items)
输出的结果呈现为:[("悲剧",3),...],该列表收录了字典中所有键值对构成的元组。
这个结果似乎并不完全符合预期。因为它是将字典中的键值对转换成元组,并将这些元组存储在列表中。然而,由于字典是无序的,所以打印出来的结果只是单纯的一个序列,我们无法直接得知哪个词的频率最高,哪个最低。尽管数据量较少时问题不大,但当数据量增大,尤其是列表中包含大量数据时,我们便难以对其进行有效处理。因此,我们需要对数据进行排序。
在进行结果排列时,我们需要运用到 sort() 函数以及 lambda 函数。
对项目进行排序,以x的第二个元素为依据,结果为降序排列。
通过这种方式,我们成功根据词汇出现的频率进行了降序排列。在排序过程中,`sort()` 函数将第一列作为排序的起始点,按照升序进行排列。然而,借助 lambda 函数这一匿名工具,我们同样能够实现以第二列为依据的降序排列。
5.输出排序后的结果
由于数据量庞大,特别是针对大文件的处理,我们往往会获得海量的信息输出。然而,根据个人需求,我们完全可以选择性地打印出排名前10位或前20位的查询结果。
for i in range(10):
word, count = items[i]
print("{0:<10}{1:>5}".format(word, count))
源代码:
txt变量通过调用open函数,以只读模式("r")成功打开了名为"hamlet.txt"的文件,并读取了其全部内容。
for ch in '# $ % & () * + , - . : ; < = > ? @ [\\] ^ {}':
txt变量中的字符ch被替换成了空字符,从而将文本中的特定特殊符号转换为了空白。
txt变量被转换成了全部小写字母的形式。
txt内容被分割,分割依据为空格,不填写任何字符。
counts = {}
for word in words:
若字典中已存在该单词,则其计数加一;若不存在,则将计数初始化为1。
excludes = {"the", "and", "of", "you", "a", "i", "my", "in"}
在遍历排除词列表的过程中,对于每一个排除词,都会将其在计数字典中的条目删除。
将counts的项转换为列表形式,即items = list(counts.items()),然后对items进行排序,以x[1]作为排序依据,并设置为降序排列,即items.sort(key=lambda x: x[1], reverse=True)。
for i in range(10):
word, count = items[i]
print("{0:<10}{1:>5}".format(word, count))
12.14日修改
有小伙伴私信说直接运行源代码会出错。是因为这一句:
words = txt.split() # 什么都不填表示用空格来分隔
这一句确实存在,位于第四行位置,不过在进行编辑处理时,并未进行换行操作,目前已对此进行了修正。
原文在我的博客网站:,欢迎大家访问