作业 4:词频统计——基本功能

一、基本信息

      1.1 本次作业的地址:https://edu.cnblogs.com/campus/ntu/Embedded_Application/homework/2088

        1.2  项目 Git地址:https://gitee.com/ntucs/PairProg.git

        1.3 结对成员:唐庆阳  1613072009

                                戴俊明  1613072010

 

二、项目分析

        2.1 程序运行模块

    2.1.1 这个函数里的循环为了计算确切行数,去掉了空行最后返回一个总的文本字符串。

 

def process_file(path, files):
    try:
        with open(path, 'r', encoding='gbk') as file:
            text = file.read()
        count = 0
        # 下面的循环为了计算行数
        for word in text.splitlines():
            if (word):
                count += 1
        print("lines:", count, file=files)#在所有需要的print参数里加入文件参数file,将输出结果添加到指定文件里
    except IOError:
        print("Read File Error!")
        return None
    return text

 

     2.1.2 对单词和词组进行序列化

      任务一:单词

      生成一个键为单个单词,值为该单词出现次数的字典。

def process_buffer(textString, file):
    """当只统计单词时(num == 1),生成<str,int>形式的键值对,
    当统计短语时,生成字典套字典的形式,具体参考sample.json文件"""
    import re
    if textString:
        word_freq = {}
        word_prelist = re.sub('(?!\’)\W', ' ', textString)
        word_list = re.sub('\s[\’]', ' ', word_prelist).lower().split()
        wordlength = word_list.__len__()
        print("words:", wordlength, file=file);

        #从stop_words.txt里图提取所有停止词,并进行过滤
        with open('stop_words.txt', 'r', encoding='gbk') as file:
            text = file.read().split()
        for word in word_list:
            if word in text:
                continue
            if word in word_freq:
                word_freq[word] += 1
            else:
                word_freq[word] = 1
    return word_freq

       任务二:多个单词组成的词组

       生成一个森林,具体数据结构参考:对英文文档中的单词与词组进行频率统计

#对词组进行统计,num为自促所包含的单词数目
def process_wordgroupcount(textString, num):
    import re
    if textString:
        word_freq = {}
        word_prelist = re.sub('(?!\’)\W', ' ', textString)
        word_list = re.sub('\s[\’]', ' ', word_prelist).lower().split()
        count = len(word_list)
        i = 0
        while 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

    return word_freq
      

 

       注:并没有使用nltk的语料库,仅仅使用一个列表作为停词表。停词表来自名为stop_words.txt的文本文件。该文本文件中包含几乎所有英文文档中的停词

    2.1.3 字典格式化

      数据已经存储到了森林中,接下来就是如何把森林格式化成普通的字典。

         相比深度优先遍历,选择的是更易理解与实现的广度优先遍历。

 

 

def format_dict(word_freq={}):
    """对统计短语的情况生成的复杂字典进行格式化,格式化后的形式为<str,int>"""
    formated_word_freq = {}
    phrases = []
    for word in word_freq.keys():
        phrases.append(word)
    index = 0
    while phrases[index] != phrases[-1]:
        phrase = phrases[index]
        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):
                temp = []
                if type(phrase).__name__ == 'str':
                    temp.append(phrase)
                else:
                    temp.extend(phrase)
                if next_word != 'Value':
                    temp.append(next_word)
                    phrases.append(temp)
        index += 1
    if len(get_dict_value(word_freq, phrases[-1])) == 1 and type(phrases[-1]).__name__ == 'list':
        formated_word_freq[' '.join(phrases[-1])] = get_dict_value(word_freq, phrases[-1])['Value']
    # print(formated_word_freq)
    return formated_word_freq

 

 

 

    2.1.4 对单词出现次数进行排序输出。

 

def output_result(word_freq, file):
    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[0], ">:", item[1], file=file)

 

     2.1.5 主函数

      进行函数参数设置和判定字母数量并把输出结构存到result.txt文件。

      将词组里的单词的数量作为参数之一。

if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument('path')         #将path作为目录加入命令行参数
    parser.add_argument('num',nargs='?')#将num作为一个可空的参数,当num为空时args.num为None
    args = parser.parse_args()
    path = args.path
    if args.num == None:
        num = 1
    else:
        num = int(args.num)
    file = open('result.txt', 'w+')
    buffer = process_file(path, file)
    if buffer:
        word_freq = process_buffer(buffer, file)
        output_result(word_freq, file)
        if num != 1:
            word_freq = process_wordgroupcount(buffer, num)
            word_freq = format_dict(word_freq)
            output_result(word_freq, file)
    file.close()

 

 

  2.2 程序算法的时间、空间复杂度分析

      2.2.1 单词

        对文本单词列表进行遍历放入字典中,时间复杂度为O(n),空间复杂度为O(n)。

      2.2.2 词组

        由于要构建森林,在对单词列表进行遍历时,要对森林的每一层查找该单词,其时间复杂度为O(n^m)(m为词组的单词个数)。又因为使用森林存储单词,其空间复杂度为O(logmn)。

        2.3 程序运行案例截图

 

三、性能分析

  1、单词的运行时间为0.5秒左右。

  

 

 

 

  2、词组的运行时间为3秒

    

 

   3.对广度优先遍历的优化

    由于广度优先遍历存在一个双向队列来存储节点,而对于大数据来说,频繁地出队与入队太消耗时间,而入队是不能避免的,所以我们只能省掉它的出队操作,以空间换时间,将原来的6秒多缩减到目前的3秒多。

 

四、其他

 

        4.1 结对编程时间开销

               经过一星期左右的探索与否定,我们修改了原本的format函数,降低了广度优先遍历的时间损耗。并且我么将原本的不给修复了一部分,比如停词,英文缩写形式等等。

        4.2 结对编程照片

              

 

五、事后分析与总结

 

        5.1 简述结对编程时,针对某个问题的讨论决策过程

    在讨论格式化森林时,唐庆阳觉得深度优先遍历的性能损耗的更少,而戴俊明觉得使用广度优先遍历的优化版本更好。事实证明,深度遍历同样需要频繁地出队与入队,而省去出队操作的广度优先遍历  在性能上更胜一筹。

 

        5.2 评价对方。

    唐庆阳对戴俊明的评价:我觉得我的伙伴对数据的存储结构以及算法有很好的了解,并能够以代码的形式实现自己的想法。在与他讨论问题地过程中,能够从他身上学到很多关于算法的知识,并且也能  够很好地听取我的意见。

    戴俊明对唐庆阳的评价:我觉得我的伙伴对python的运用上十分出色,尤其在用正则处理文档中英文缩写的情况减少了不少时间。而且,我的伙伴沟通良好,善于总结,不断地测试每一段的代码,将此  解决方案的性能优化到极致。

 

        5.3 评价整个过程:关于结对过程的建议

    提议设置更加开放的题目与需求,结对编程过程中,我们常因为一项需求而导致抛弃性能更加优越的解决方案。

 

        5.4 其它

    python拥有成熟的大数据分析的库,对于初学者来说,使用这些库还是有点困难的。

posted @ 2018-10-20 21:16  emiyak  阅读(401)  评论(1编辑  收藏  举报