1.程序运行模块(方法、函数)介绍
def process_file(dst): # 读文件到缓冲区,统计文本行数 try: # 打开 file = open(dst, ‘r‘) # dst为文本的目录路径 except IOError as e: print(e) return None try: # 读文件到缓冲区,统计文本行数 lines = len(file.readlines()) # 关闭文件,重新打开 file.close() file = open(dst, "r") bvffer = file.read() except: print("Read File Error!") return None file.close() return bvffer, lines
def process_buffer(bvffer): # 处理缓冲区,返回存放每个单词频率的字典word_freq,单词总数 if bvffer: word_freq = {} # 将文本内容都小写 bvffer = bvffer.lower() # 用空格消除文本中标点符号 words = bvffer.replace(punctuation, ‘ ‘).split(‘ ‘) # 正则匹配至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写 regex_word = "^[a-z]{4}(\w)*" for word in words: if re.match(regex_word, word): # 数据字典已经存在该单词,数量+1 if word in word_freq.keys(): word_freq[word] = word_freq[word] + 1 # 不存在,把单词存入字典,数量置为1 else: word_freq[word] = 1 return word_freq, len(words)
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[:10]
def save_result(lines, words, items): # 保存结果到文件(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 + "\n") for item in items: item = ‘<‘ + str(item[0]) + ‘>:‘ + str(item[1]) + ‘\n‘ result.write(item) print(‘写入result.txt已完成‘) result.close()
if __name__ == "__main__": # 命令行传递参数 parser = argparse.ArgumentParser() parser.add_argument(‘dst‘) args = parser.parse_args() dst = args.dst bvffer, lines = process_file(dst) word_freq, words = process_buffer(bvffer) items = output_result(word_freq) # 把lines、words类型强制转化为str lines = str(lines) words = str(words) save_result(lines, words, items)
def process_buffer(bvffer): # 处理缓冲区,返回存放每个单词频率的字典word_freq,单词总数 if bvffer: word_freq = {} # 将文本内容都小写 bvffer = bvffer.lower() # 用空格消除文本中标点符号 words = bvffer.replace(punctuation, ‘ ‘).split(‘ ‘) # 正则匹配至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写 regex_word = "^[a-z]{4}(\w)*" # 停词表模块 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 re.match(regex_word, word): # 数据字典已经存在该单词,数量+1 if word in word_freq.keys(): word_freq[word] = word_freq[word] + 1 # 不存在,把单词存入字典,数量置为1 else: word_freq[word] = 1 return word_freq, len(words)
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("频率前五的二元词组") # 这里的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.程序算法的时间、空间复杂度分析
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[:10]
时间复杂度:sort函数使用的Timsort算法,其最Best Case下时间复杂度为O(n),Average Case下时间复杂度为O(nlog2n),Worst Case下时间复杂度为O(nlog2n);
for循环的时间复杂度为O(n);所以该段代码的时间复杂度:Best Case:O(n), Average Case:O(nlog2n) ,Worst Case:O(nlog2n)
空间复杂度:sort函数使用的Timsort算法空间复杂度为O(n),for循环的空间复杂度也为O(n),所以该段代码的空间复杂度为O(n)
3.程序运行案例截图
(3)Task2.2 高频词组
三、性能分析(把主函数的语句用main()函数封装,在主函数运行性能测试代码)
PSP | 任务内容 | 预估耗时(min) | 实际耗时(min) |
Planning | 计划 | 40 | 50 |
Coding Standard | 代码规范 | 10 | 10 |
Coding | 具体编码 | 180 | 200 |
Code Review | 代码复审 | 30 | 25 |
Test And Improve | 性能测试及改进 | 40 | 50 |
Reporting | 撰写博客以及push码云 | 100 | 100 |
Postmortem | 总结 | 10 | 15 |
合计 | 410 | 450 |
一开始准备使用nltk中的停词表,但是考虑到时间开销以及停词效果显示方面的原因,我们选择创建stopwords.txt,自定义停词内容,然后通过代码读取txt文档中停用词,在输出词频前十的过程中进行剔除停用词。
(1)钱金评价高耀:①高耀同学学习能力强、对于不熟悉的方法上手很快。表现在:Task2中要求实现统计高频短语,高耀同学快速掌握了 nltk(Natural LanguageToolkit,自然语言处理工具包)的使用方法。②高耀同学做事认真且有条理、但是严谨性需加强。表现在:编写博客层次清晰有条理,但是对于代码的容错机制欠缺。
(2)高耀评价钱金:①钱金同学思维活跃、常常想出好的方法。表现在:Task2中要求实现统计高频短语,钱金同学想出使用正则表达式的方法来匹配短语。②钱金同学的基础代码能力欠缺,需要继续努力。
(1)可以以自由结对编程的形式开展,同学自主寻找的结对伙伴彼此比较熟悉能够更有效率地开展结对编程工作;当然,不太熟悉的人结对编程也有一定好处,如可以锻炼个人的与他人交流沟通、相处之道。
(1)大多数人偏好 “单打独斗”,只愿一个人完成整个功能的实现,而忽视了这种做法存在的致命缺陷——主观意愿过强;而结对作业不仅提供了一个能从客观角度帮助你分析的队友,还提供了一种结对编程形式的模板——其中一人主攻编码模块,另一人则更客观提出编码意见促进编码实现,这也算是一种不可多得的编程体验吧。
原文:https://www.cnblogs.com/KingGY/p/9800179.html