对英文文档中的单词与词组进行频率统计
一、程序分析
1、以只读模式读取文件到字符串
def process_file(path):try:with open(path, 'r') as file:text = file.read()except IOError:print("Read File Error!")return None return text
2、对字符串进行数据清洗,返回一个字典
import re word_list = re.sub('[^a-zA-Z0-9n]', ' ', textString).lower().split()
使用正则表达式过滤掉文档中的特殊字符,把它们全部替换为空格,方便后续的分隔操作。(忽略大小写,所以全部使用小写字母)
2.1、只考虑单词频率统计
for word in word_list:if word in word_freq:word_freq[word] += 1else:word_freq[word] = 1
判断单词列表中的单词是否在单词频率字典中。
如果这个单词在字典中,则该单词的个数加1;
如果这个单词不在字典中,则以这个单词为键,赋值为1,表示这个单词第一次出现。
2.2、考虑单词和词组的频率
2.2.1、数据结构
词组是由单词连接构成的,一个单词既可以与前面的单词构成词组,也可以与后面的单词构成词组。
同时,一个单词可能在文章中多次出现,并且和前后的单词构成多种不同的词组。
这也就表示几乎每一个单词可以一前一后发散出去,这与图状结构颇为类似。(适用于两个单词构成的词组)
选择图状结构与当前的问题颇为契合。但是,目前python没有一种已知的图类来供我们操作。(自定义类暂不作考虑)
于是我想到了树状结构(两个以上单词构成的词组也适用),砍去了单词向前的发散,只保留向后的。至此,问题就变成了构建森林。
而在python中,森林是比较容易表示的。用一个字典放置每一棵树的根节点,字典套字典,就形成了森林。
可能你们要问单词和词组的统计个数放在哪。我使用“Value”作键,键值number这样一种结构放在该单词的字典中。
具体的字典示例样本参见sample.json
2.2.2、具体流程
以索引停在50,词组限制单词个数为3为例:
(1)在树的根节点中寻找mother节点,找不到就创建mother节点。
"mother":{"Value":1}
(2)在树的根节点中寻找your节点,找到了继续寻找mother节点,找不到就创建mother节点。(不可能找不到,因为索引经过49之后肯定存在your根节点)
(3)以此类推,在树的根节点中寻找did节点,找到了继续寻找your节点,,找到了继续寻找mother节点,找不到就创建mother节点......
具体实现:
count = len(word_list)i = 0while i < count: # 因为需要用到索引遍历列表,只能使用while来遍历列表 finish = i start = i - num + 1 # num表示词组的单词个数限制,start表示以该单词作为词组结尾的第一个单词的索引 if start < 0: start = 0 # 处理开始时索引前面没有单词的特殊情况 index = i while index >= start: # 做num次建立节点 if word_list[i] in get_dict_value(word_freq, word_list[index: finish]).keys(): get_dict_value(word_freq, word_list[index: finish])[word_list[i]]['Value'] += 1 else: get_dict_value(word_freq, word_list[index: finish]).update({word_list[i]: {'Value': 1}}) index -= 1 i += 1
get_dict_value函数
def get_dict_value(word_freq={}, keys=[]):"""如果keys为字符串,返回word_freq字典中以keys为键的值。如果keys为列表,则使用eval()函数进行字符串拼接,深度查找word_freq字典中以keys为键的值。"""if type(keys).__name__ == 'str':return word_freq[keys]else:count = len(keys)if count == 0:return word_freqelif count == 1:return word_freq[keys[0]]elif count == 2:return word_freq[keys[0]][keys[1]]elif count == 3:return word_freq[keys[0]][keys[1]][keys[2]] #对寻找三个单词以下的词组进行特化else:string = "word_freq['"string += "']['".join(keys)string += "']"return eval(string) #动态寻找字典的值的一般版本
2.2.3、字典格式化
数据已经存储到了森林中,接下来就是如何把森林格式化成普通的字典。
相比深度优先遍历,我选择的是更易理解与实现的广度优先遍历。
广度优先遍历的原理我不再赘述。
def format_dict(word_freq={}):"""对统计短语的情况生成的复杂字典进行格式化,格式化后的形式为<str,int>"""formated_word_freq = {}phrases = []for word in word_freq.keys(): #将所有根节点放入队列中phrases.append(word)while len(phrases) > 0: #只要队列还有元素,就表明还没有遍历结束phrase = phrases[0]if len(get_dict_value(word_freq, phrase)) == 1 and type(phrase).__name__ == 'list':formated_word_freq[' '.join(phrase)] = get_dict_value(word_freq, phrase)['Value'] #搜索到叶子节点了,这个节点存入格式化好的字典中else:for next_word in get_dict_value(word_freq, phrase): #除"Value"键值对以外的键都入队temp = []if type(phrase).__name__ == 'str':temp.append(phrase)else:temp.extend(phrase)if next_word != 'Value':temp.append(next_word)phrases.append(temp)phrases.pop(0) #搜索完队列的第一个节点的子节点,这个节点出队# print(formated_word_freq)return formated_word_freq
3、输出字典(没有改动)
def output_result(word_freq):if word_freq:sorted_word_freq = sorted(word_freq.items(), key=lambda v: v[1], reverse=True)for item in sorted_word_freq[:10]:print(item)
4、主函数
if __name__ == "__main__":import argparseparser = argparse.ArgumentParser()parser.add_argument('path') #路径parser.add_argument('num') #词组单词个数args = parser.parse_args()path = args.pathnum = int(args.num)buffer = process_file(path)if buffer:word_freq = process_buffer(buffer, num)if num != 1:word_freq = format_dict(word_freq)output_result(word_freq)
命令行接受两个参数,一个是英文文档的路径,还有一个是构成一个词组的最大单词个数(为1时即单词统计)。没有这个限制,森林里就会出现一棵从第一个单词到最后一个单词的树。
二、代码风格说明
基本遵从PEP8,PEP8 涵盖了诸如空格、函数/类/方法之间的换行、import
、对已弃用功能的警告之类的寻常东西,是一个不错的准则。
def get_dict_value(word_freq={}, keys=[]):"""如果keys为字符串,返回word_freq字典中以keys为键的值。如果keys为列表,则使用eval()函数进行字符串拼接,深度查找word_freq字典中以keys为键的值。"""if type(keys).__name__ == 'str':return word_freq[keys]else:count = len(keys)if count == 0:return word_freqelif count == 1:return word_freq[keys[0]]elif count == 2:return word_freq[keys[0]][keys[1]]elif count == 3:return word_freq[keys[0]][keys[1]][keys[2]] #对寻找三个单词以下的词组进行特化else:string = "word_freq['"string += "']['".join(keys)string += "']"return eval(string) #动态寻找字典的值的一般版本
注释基本也只在关键地方才有,不必面面俱到。
三、程序运行命令、运行结果截图
运行命令:
python statistic.py Gone_with_the_wind.txt 1
python statistic.py Gone_with_the_wind.txt 2
四、简单性能分析
运行命令:
python -m cProfile -o result.out -s cumulative statistic.py Gone_with_the_wind.txt 2
python gprof2dot.py -f pstats result.out | dot -Tpng -o result.png
单词统计性能分析:
词组统计性能分析:
在进行单词统计时,时间有五成花费在过滤特殊字符上,有三成花费在创建字典上。
而在词组统计中,过滤特殊字符只占了一成,两层时间在创建森林,六成时间在格式化森林。其中,尤其以list的pop()函数占用时间最多,将近一半的时间用来出队。
程序优化:尝试在不pop()得情况下修改广度优先遍历。尝试另一种数据结构,森林比图占的内存多。
修改中...
转载于:https://www.cnblogs.com/SuccessfullyReleased/p/9745258.html
对英文文档中的单词与词组进行频率统计相关推荐
- 一篇英文文档中找出频数最多的10个单词
"""一篇英文文档中找出频数最多的10个单词collections: Counter 提供计数器工具以支持方便和快速的计数 most_common(n) 返回n个最常见元 ...
- python中怎么统计英文字符的个数_使用python统计英文文档中的字母占比和词频
本文主要介绍如何使用python软件进行统计文档中各字母出现概率和数量最多单词.程序中用到的部分库文件需自行下载,可参考网址:https://www.lfd.uci.edu/~gohlke/pytho ...
- py爬取英文文档学习单词
最近开始看一些整本整本的英文典籍,虽然能看个大概,但是作为四级都没过的我来说还是有些吃力,总还有一部分很关键的单词影响我对句子的理解,因为看的是纸质的,所以查询也很不方便,于是想来个突击,我想把程序单 ...
- 【搞事情】英文文档单词对比自动翻译
problem 可能的背景知识:python3:c++:dos&bat:World:Excel:PDF: 给定两个英文文档(约会大作战3PDF版&高中英语词汇Word版) 求两文档共同 ...
- java统计每个单词单词出现的次数_Java 读取一段英文文档统计每个单词出现的次数和单词的总数...
Java 读取当前目录下一段英文文档统计每个单词出现的次数和单词的总数 英文文档名字为 english.txt代码如下import java.util.*;import java.util.regex ...
- react中文文档、英文文档及JavaScript相关文档及web前端相关资料
一. react中文文档 https://doc.react-china.org 二. react英文文档 https://reactjs.org 三.react Github https://git ...
- java api 英文_教你查阅Java API 英文文档(JDK 11)
然后找到"Specifications"并点击 API Documentation 比如我们在别人的源码里看到了 方法[也叫函数]: Scanner input = new Sc ...
- 记录平时编程或者阅读英文文档的时候不认识的英文单词
一.目的 英语虽然过了4级,但是还是很多英文单词不认识,为了以后能更好的阅读英文文档和函数的英文注释,记录自己不认识的英文单词,方便以后复习,这里后面会持续更新,因为放在网上这个平台不会弄丢. 二.不 ...
- [转]Postgres-XL 10r1英文文档
Postgres-XL 是一个完全满足ACID的.开源的.可方便进行水平扩展的.多租户安全的.基于PostgreSQL的数据库解决方案. Postgres-XL 可非常灵活的应用在各类场景中,比如: ...
最新文章
- 7年前轰动全球的Science论文,被发现可能搞错了
- 【Python】unicode' object is not callable
- Python(四)字符串
- [转]VC++中对文件的写入和读取
- es6 混合commjs_详谈commonjs模块与es6模块的区别
- CopyOnWriteArrayList源码
- LiveVideoStack成立5周年生日快乐!一路走来,感谢有你!
- 点击头像显示大图Dialog
- TensorFlow2.0:索引和切片(2)
- python pdf转word
- pycharm中的常用快捷键与常用设置
- 基于双向长短期记忆神经网络【biLSTM】模型的污染数据预测实战
- 抖音康辉机器人_央视主持人太会玩!康辉录抖音,笑死了!
- linux 文件 内容 并集,Linux 两个文件求交集、并集、差集
- 百度地图-手动JS触发自定义Marker覆盖物点击事件
- Java学习笔记001_概述及环境搭载
- python第三方库汇总
- 网页崩溃原因软件测试,支招:原来这些才是APP崩溃的主要原因!资深技术大牛测试经验总结...
- tui-editor富文本编辑器组件
- 借款必须先买商品再折旧,分期易和通联支付联合收割借款人,年化利率高达240%
热门文章
- 交叉熵损失函数公式_交叉熵损失函数对其参数求导
- linux如何用vi编程,vi使用方法
- java鼠标样式设置,设置Echarts鼠标悬浮样式
- instagram api java_如何在没有用户交互的情况下获得instagram access_token(新api)?...
- 学计算机高考英语听力考试时间,北京高考英语听力考试时间
- GT Transceiver中的重要时钟及其关系(5)QPLL的工作原理介绍
- 使用未编译的XAML动态生成WPF控件
- 国家航天局:中国空间站预计到2022年前后建成
- oracle数据库实现不同数据库之间的表格数据定期同步
- 内存管理[6]测试堆的内存占用情况