作业四词频统计----基本功能
一 、基本信息
1.本次作业的地址: https://edu.cnblogs.com/campus/ntu/Embedded_Application/homework/2088
2.项目Git的地址:https://gitee.com/ntucs/PairProg/tree/SE026 027
3.开发环境:Python3.6、Pycharm2018
4.结对成员:1613072026 唐顺成、1613072027 吴涛
二、项目分析
1、程序运行模块(方法、函数)介绍
Task1:
(1)读文件到缓冲区,统计文本行数
def process_file(dst): # 读文件到缓冲区 try: # 打开文件 f = open(dst, 'r') # path为文件路径 except IOError as s: print(s) return None try: # 读文件到缓冲区 count = 0 # 如果文件很大,那么放到列表里计算长度的方法将会很慢,所以循环会更好些 for count, line in enumerate(f): count += 1 f.close() f = open(dst, 'r') bvffer = f.read() except: print('Read File Error!') return None f.close() return bvffer, count
(2)处理缓冲区,返回存放每个单词频率的字典word_freq,单词总数
def process_buffer(bvffer): # 处理缓冲区,返回存放每个单词频率的字典word_freq if bvffer: # 下面添加处理缓冲区bvffer代码,统计每个单词的频率,存放在字典word_freq word_freq = {} # 用空格代替标点符号,并且去掉大小写,之后进行正则匹配 bvffer = bvffer.replace(punctuation, '').lower().split(' ') regex_word = "^[a-z]{4}(\w)*" words = [] for word in bvffer: # 判定是否符合单词的定义 if re.match(regex_word, word): words.append(word) for word in words: if word in word_freq.keys(): # 数据字典已经存在该单词,数量+1 word_freq[word] = word_freq[word] + 1 else: # 不存在,把单词存入字典,数量置为1 word_freq[word] = 1 return word_freq, len(words)
(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]: # 输出 Top 10 的单词 print('<' + str(item[0]) + '>:' + str(item[1])) return sorted_word_freq
(4)保存结果到文件result.txt
def save_result(lines, words_number, sorted_word_freq): # 保存结果到文件(result.txt) try: result = open("result.txt", "w") # 以写模式打开,并清空文件内容 except Exception as e: result = open("result.txt", "x") # 文件不存在,创建文件并打开 # 写入文件result.txt result.write("lines:" + lines + "\n") result.write("words:" + words_number + "\n") for item in sorted_word_freq[:10]: item = '<' + str(item[0]) + '>:' + str(item[1]) + '\n' result.write(item) print('写入result.txt已完成') result.close()
(5) 主函数调用之前封装的函数
if __name__ == "__main__": dst = "Gone_with_the_wind.txt" bvffer, lines = process_file(dst) word_freq, words_number = process_buffer(bvffer) sorted_word_freq2 = output_result(word_freq) # 把lines、words类型强制转化为str lines = str(lines) words_number = str(words_number) save_result(lines, words_number, sorted_word_freq2)
Task2:
(1)听词表模块
def process_buffer(bvffer): # 处理缓冲区,返回存放每个单词频率的字典word_freq if bvffer: # 下面添加处理缓冲区bvffer代码,统计每个单词的频率,存放在字典word_freq word_freq = {} # 用空格代替标点符号,并且去掉大小写,之后进行正则匹配 bvffer = bvffer.replace(punctuation, '').lower().split(' ') regex_word = "^[a-z]{4}(\w)*" words = [] for word in bvffer: # 判定是否符合单词的定义 if re.match(regex_word, word): words.append(word) txtWords = open("stopwords.txt", 'r').readlines() # 读取停词表文件 stopWords = [] # 存放停词表的list # 读取文本是readlines所以写入list要将换行符取代 for i in range(len(txtWords)): txtWords[i] = txtWords[i].replace('\n', '') stopWords.append(txtWords[i]) for word in words: if word not in stopWords: # 当单词不在停词表中时,使用正则表达式匹配 if word in word_freq.keys(): # 数据字典已经存在该单词,数量+1 word_freq[word] = word_freq[word] + 1 else: # 不存在,把单词存入字典,数量置为1 word_freq[word] = 1 return word_freq, len(words)
(2)高频词组模块(使用nltk.collocations下的两个类BigramCollocationFinder、 TrigramCollocationFinder对高频率词组进行统计)
def word_group(dst): # 统计高频的二元词组、三元词组BigramCollocationFinder、 TrigramCollocationFinder str = open(dst, 'r').read() # 用空格消除文本中标点符号 wordGroup = str.lower() tokens = nltk.wordpunct_tokenize(wordGroup) # 二元词组 finder = nltk.collocations.BigramCollocationFinder.from_words(tokens) # 过滤掉符合条件fn的词组 finder.apply_word_filter(lambda x: x in [',', '.', '’', '“', '”', '\'', '"', ',"', ',”']) print("高频短语:") print("高频率二字短语") # 这里的key是排序依据,就是说先按t[1](词频)排序,-表示从大到小;再按照词组(t[0])排序,默认从a-z. print(sorted(finder.ngram_fd.items(), key=lambda t: (-t[1], t[0]))[:5]) # 三元词组 finder = nltk.collocations.TrigramCollocationFinder.from_words(tokens) # 过滤掉符合条件fn的词组 finder.apply_word_filter(lambda x: x in [',', '.', '’', '“', '”', '\'', '"', ',"', ',”']) print("高频三字短语") print(sorted(finder.ngram_fd.items(), key=lambda t: (-t[1], t[0]))[:5])
2、程序算法的时间、空间复杂度分析
以下面代码为例:
count = 0 for count, line in enumerate(f): count += 1 f.close()
注:统计文件行数时其实可以用这行代码:count = len(open(filepath, 'r').readlines()),但有时因为文件过大,速度将会变得很慢,所以改用统计文件函数 enumerate()。
时间复杂度:该段代码只有一个循环,且与文件的大小有关,其时间复杂度为O(n)。
空间复杂度:该段循环没有像readlines()那样需要产生一个数组统计,所以开销为0,空间复杂度为O(1)。
3、程序运行截图
(1)Task1中resul.txt
(2)Task2停词模块
(3)Task2高频率词组模块
三、性能分析
Task2:
四、合作编程
1.合作编程时间开销
PSP | 任务内容 | 实际耗时/min |
Planning | 计划 | 30 |
Coding Standard | 代码规范 | 15 |
Coding | 具体编码 | 170 |
Code Review | 代码复审 | 30 |
Test And Improve | 性能测试及改进 | 50 |
Reporting | 撰写博客以及push码云 | 70 |
Postmortem | 总结 | 15 |
总计 | 380 |
2.结对编程照片
五、事后分析与总结
1.简述关于停词表部分的决策过程
一开始准备使用nltk中的停词表,但是考虑到时间开销以及停词效果显示方面的原因,我们选择创建stopwords.txt,自定义停词内容,然后通过代码读取txt文档中停用词,在输出词频前十的过程中进行剔除停用词。
2.评价
(1)吴涛评价唐顺成:①唐顺成同学学习能力强、能很快学习了解一个新的编程方式。能教会我这个编程能力差的学生很多②唐顺成同学做事认真且有条理。
(2)唐顺成评价吴涛:①吴涛同学的编程能力不强但是,思维开阔。②吴涛同学的编程能力欠缺,需要继续跟我好好学习。
3.关于结对过程的建议与看法
自由合作编程,有利于好同学帮助普通的学生完成困难的作业,并且提升自己编程能力。同学自主寻找的合作伙伴彼此比较熟悉能够更有效率地开展合作编程工作,这是未来工作的缩影。