2019 软件工程 春季 第2次作业
2019 软件工程 春季 第2次作业
——Python统计单词词频
1. 在文章开头给出代码仓库中项目地址
作业Github地址:https://gitee.com/zhangzhen12a/shuzu
2. 给出PSP表格,分析估计值与真实值的区别
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
30 |
30 |
· Estimate |
估计这个任务需要多少时间 |
480 |
670 |
Development |
开发 |
440 |
530 |
· Analysis |
需求分析 (包括学习新技术) |
120 |
150 |
· Design Spec |
· 生成设计文档 |
30 |
20 |
· Design Review |
· 设计复审 |
30 |
20 |
· Coding Standard |
代码规范 (为目前的开发制定合适的规范) |
20 |
20 |
· Design |
· 具体设计 |
30 |
50 |
· Coding |
· 具体编码 |
120 |
150 |
· Code Review |
· 代码复审 |
30 |
30 |
· Test |
测试(自我测试,修改代码,提交修改) |
60 |
90 |
Reporting |
报告 |
80 |
110 |
· Test Repor |
· 测试报告 |
30 |
60 |
· Size Measurement |
· 计算工作量 |
20 |
20 |
· Postmortem & Process Improvement Plan |
事后总结,并提出过程改进计划 |
30 |
30 |
合计 |
550 |
670 |
3. 建立每日软件工程学习日志,格式自定,但要体现学习时段、学习内容、收获体会、自我效率评价等
日期 |
学习时段 |
学习内容 |
收获体会 |
效率评价 |
4-8 |
9-12 |
Python编程 |
常用操作符 |
较低 |
4-9 |
19-21 |
作业 |
初步了解 |
较高 |
4-10 |
10-12 |
Python编程 |
常用操作符 |
较高 |
4-11 |
15-17 |
作业 |
开始制作 |
较高 |
4-12 |
20-21 |
Python编程 |
分支和循环 |
较低 |
4-13 |
20-22 |
Python编程 |
分支和循环 |
较高 |
4. 设计实现过程。设计包括代码如何组织,比如会有几个类,几个函数,他们之间关系如何,关键函数是否需要画出流程图?单元测试是怎么设计的?分析单元测试的合理性与充分性
本设计的目的是实现一个能够对文本文件中的单词的词频进行统计的控制台程序,代码可以按照,读取文件到缓冲区;统计文件的有效行数;统计文件的单词总数;统计每个单词的频率;输出频率最高的前10个词组并排序;这5个函数来实现,他们之间是递进关系,单元测试通过随机生成若干个临时文件,利用编写好的程序统计文件中的单词的词频,检查是否正确,通过测试空文本等特殊文本来保证单元测试的充分性。
5. 记录在改进程序性能上所花费的时间,描述你改进的思路,并展示一张性能分析图(由性能分析工具自动生成),并展示你程序中消耗最大的函数
可以看出,在处理缓冲区,统计每个单词的频率阶段程序耗时最多。
6. 代码说明。展示出项目关键代码,并解释思路与注释说明
1. 读文件到缓冲区
def process_file(dst): # 读文件到缓冲区 try: # 打开文件 file = open(dst, 'r') # dst为文本的目录路径 except IOError as s: print (s) return None try: # 读文件到缓冲区 bvffer = file.read() except: print ("Read File Error!") return None file.close() return bvffer
2. 处理缓冲区,统计每个单词的频率
def process_buffer(bvffer): if bvffer: word_freq = {} # 下面添加处理缓冲区 bvffer代码,统计每个单词的频率,存放在字典word_freq # 将文本内容都改为小写 bvffer = bvffer.lower() #去除文本中的中英文标点符号 for ch in '“‘!;,.?”': bvffer = bvffer.replace(ch, " ") # strip()删除空白符(包括'/n', '/r','/t');split()以空格分割字符串 words = bvffer.strip().split() for word in words: word_freq[word] = word_freq.get(word, 0) + 1 return 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]: # 输出 Top 10 的单词 print (item)
4. 主函数,将前面的函数进行调用封装
if __name__ == "__main__": import argparse dst = "D:\work\wordcount\Gone_with_the_wind.txt" bvffer = process_file(dst) word_freq = process_buffer(bvffer) output_result(word_freq)
5. 性能分析
def touch_test_file(line_num, word_num): """创建测试文件,随机生成字符,用于测试""" _x = Xeger() words = lambda: _x.xeger(r'[a-zA-Z][a-zA-Z0-9]*') # 随机生成有效单词 non_word = lambda: _x.xeger(r'\d[a-zA-Z0-9]*') # 随机生成开头为数字的单词 separator = lambda: _x.xeger(r'[^a-zA-Z0-9\n\r]') # 随机生成非字母数字回车换行符的字符 space = lambda: _x.xeger(r'\n[\s]*\n') # 随机生成回车空白字符回车 # 统计生成的文件中字符、单词、有效行、词频 result = {'chars': 0, 'words': word_num * line_num, 'lines': line_num, 'container': {}} # 创建文件,随机生成字符 file_obj = open(TEMP_FILE, 'w') for _ in range(line_num): for _ in range(word_num): word = words() chars = word + separator() + non_word() + separator() result['chars'] += len(chars) result['container'][word.lower()] = result['container'].get(word.lower(), 0) + 1 file_obj.write(chars) chars = space() result['chars'] += len(chars) file_obj.write(chars) file_obj.close() # 获取排序后的词频结果 sort_result = sorted(result['container'].items(), key=lambda x: (-x[1], x[0]))[:10] result['container'] = sort_result return result class TestWordCont(unittest.TestCase): """Test for WordCont""" def test_container(self): """词频测试""" self.assertEqual(handle.container(), result['container']) result = touch_test_file(100, 40) handle = WordCont.FileHandle(TEMP_FILE) os.remove(TEMP_FILE) if __name__ == '__main__': unittest.main()
7. 结合在构建之法中学习到的相关内容与个人项目的实践经历,撰写解决项目的心路历程与收获
1. 当开始一个项目时,一定要首先分析项目的重难点,时间节点等内容,将项目分为一个个小项目,并根据PSP表对自己的完成情况进行较为精确的管理
2. 在项目过程中,要和别人多讨论交流,善于借鉴、学习、吸收他人的想法,学会利用已有的一些代码程序,可以达到事半功倍的效果
3. 编写完程序后不代表结束,应该对程序进行合理和充分的检验,还应不断完善代码,去除冗余程序,不断提高程序的运行效率