对英文文档中的单词与词组进行频率统计

一、程序分析

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] += 1
      else:
           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_freq
        elif 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 argparse

    parser = argparse.ArgumentParser()
    parser.add_argument(‘path‘) #路径
    parser.add_argument(‘num‘) #词组单词个数
    args = parser.parse_args()
    path = args.path
    num = 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_freq
        elif 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

时间: 2024-08-01 20:56:26

对英文文档中的单词与词组进行频率统计的相关文章

一篇英文文档中找出频数最多的10个单词

"""一篇英文文档中找出频数最多的10个单词collections: Counter 提供计数器工具以支持方便和快速的计数 most_common(n) 返回n个最常见元素及其计数的列表,从最常见到最少. 如果省略nNone,则 most_common()返回计数器中的所有元素."""import refrom collections import Counter# print(dir(Counter))with open('english.tx

统计英文文档频率前n单词

#coding:utf-8 #!/usr/bin/python2.6 def statistic_eng_text(): '''统计出英文文档中高频词汇''' cnt = Counter() np = os.path.join(get_project_path(),'doc','jack lodon.txt') ff = open(np,'r') words = ff.read() format_text = re.split('[\s\ \\,\;\.\!\n]+',words) for w

py爬取英文文档学习单词

最近开始看一些整本整本的英文典籍,虽然能看个大概,但是作为四级都没过的我来说还是有些吃力,总还有一部分很关键的单词影响我对句子的理解,因为看的是纸质的,所以查询也很不方便,于是想来个突击,我想把程序单词收拢在一起学习一下,希望这样的更有针对性一些,因为你想,arbitrary (任意的,武断的)这样的单词不太可能会出现在技术文档上,学了这样的单词对理解英文技术文档没有太大帮助.所以今天花了几个小时研究了一下,发现是很可行的,实现也不算难.步骤主要是以下几点,第一:先搞定翻译接口.翻译的来源分为接

软件开发中 常见英文文档 缩写(转)

软件开发中常见英文缩写和各类软件开发文档的英文缩写: 英文简写 文档名称 MRD market requirement document (市场需求文档) PRD product requirement document (产品需求文档) SOW 工作任务说明书 PHB Process Handbook (项目过程手册) EST Estimation Sheet (估计记录) PPL Project Plan (项目计划) CMP Software Management Plan( 配置管理计划

Nagios 插件开发英文文档网址

http://nagios-plugins.org/doc/guidelines.html#PREFACE Nagios 插件开发英文文档网址,布布扣,bubuko.com

如何看英文文档?

发现自己没有看英文文档的能力,一是看不进去,二是勉强看进去但是很累,往往看了后面就忘了前面的.太长的文档基本需要很长时间才能看懂. 怎么办? 以后就把英文文档直接下载下来,然后用文本编辑器打开,看一句翻译一句.直接自己搞汉化.这样不仅印象深刻,再次复习的时候也能快速的看懂. 虽然笨了点,效率查了点,但是是个好方法.相信坚持下来还是会有所收获的.以后自己英文文档的阅读能力也会随着翻译的数量的增加而提高的. 纯英文的文档看完了还可以分享的网络上,也算有分享精神,而且,如果哪里有不正确的地方也许网友可

PHP-redis英文文档

作为程序员,看英文文档是必备技能,所以尽量还是多看英文版的^^ PhpRedis The phpredis extension provides an API for communicating with the Redis key-value store. It is released under the PHP License, version 3.01. This code has been developed and maintained by Owlient from November

openstack【Kilo】汇总:包括20英文文档、各个组件新增功能及Kilo版部署

OpenStack Kilo版本发布 20英文文档OpenStack Kilo版本文档汇总:各个操作系统安装部署.配置文档.用户指南等文档 Kilo版部署 openstack[Kilo]入门 [准备篇]零:整体介绍 openstack[Kilo]入门 [准备篇]一: Ubuntu14.04远程连接(ssh安装) openstack[Kilo]入门 [准备篇]二:NTP安装 openstack[Kilo]入门 [准备篇]三:mysql(MariaDB)安装[控制节点] openstack[Kilo

python3 怎么统计英文文档常用词?(附解释)

# coding: utf-8 # In[32]: #import requests #from bs4 import BeautifulSoup #res = requests.get("http://www.guancha.cn/america/2017_01_21_390488_s.shtml") #res.encoding = 'utf-8' #soup = BeautifulSoup(res.text,'lxml') # In[66]: speech_new = open(&