软件工程个人项目
软件工程 | 班级链接 |
---|---|
作业要求 | 作业链接 |
github链接 | github |
作业目标 | 设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率 |
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | 10 | 10 |
Estimate | 估计这个任务需要多少时间 | 12 | 12 |
Development | 开发 | 120 | 150 |
Analysis | 需求分析 (包括学习新技术) | 25 | 36 |
Design Spec | 生成设计文档 | 15 | 12 |
Design Review | 设计复审 | 5 | 5 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 5 | 5 |
Design | 具体设计 | 10 | 14 |
Coding | 具体编码 | 40 | 56 |
Code Review | 代码复审 | 5 | 5 |
Test | 测试(自我测试,修改代码,提交修改) | 45 | 60 |
Reporting | 报告 | 50 | 75 |
Test Report | 测试报告 | 10 | 10 |
Size Measurement | 计算工作量 | 3 | 3 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 10 | 10 |
合计 | 365 | 463 |
需求分析
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
- 原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
- 抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
- 从命令行参数给出:论文原文的文件的绝对路径。
- 从命令行参数给出:抄袭版论文的文件的绝对路径。
- 从命令行参数给出:输出的答案文件的绝对路径。
我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位
程序设计与实现
将文本的内容进行一个分词处理,使用自然语言库jieba,将处理好的两份分词结果合并得到一个共同的集合,随后统计每一个分词在总的词库当中的词频信息,根据词频信息得到两个词频向量,随后计算这两个向量的余弦相似度,从而获得两个文本的相似程度。
对于余弦相似度的获取,使用了两种方法。
方法一使用函数duplicate_check_function_1,思路是直接将文本的内容全部进行分词处理,对所有的词汇计算一个词频再计算它的余弦相似度。
方法二使用三个函数duplicate_check_function_2、calculate_similarity和func,思路不是利用所有词汇进行内容的分词处理,而是统计高频的词汇权重,仅只用这些词汇进行余弦度的计算。即首先调用两次duplicate_check_function_2函数对传入的两个文本分别进行提取关键字处理,然后再调用两次calculate_similarity函数对两个文本分别进行相似度计算,最后调用func函数返回查重结果。
性能分析
以下Pycharm以Profile模式运行时生成的性能分析图
图中可以清楚的看到函数之间的调用关系、调用次数和执行时间等信息,可以看出,查重过程中用于进行余弦相似度计算的两个函数和用于分词处理的函数运行时间占了程序总执行时间的大部分,该部分为整个程序的主体部分
覆盖率测试
从下图可以看出,覆盖率达到了91%,其余未运行到的部分用于处理异常,覆盖率很高
单元测试和异常处理
- 1.本测试向函数中传入两个一样的文本,理论上的结果应该是1,代码如下:
def test_same_file(self):
duplicate_check_function_1("D:\origi.txt","D:\origi.txt")
- 2.本测试向函数中传入两个空文本,没有任何内容,通过捕获异常并打印输出结果,显示要输入正确的文本,代码如下:
def test_empty_file(self):
duplicate_check_function_1("D:\oigiempty.txt","D:\oigiempty.txt")
- 3.本测试向函数中输入两个错误的路径,通过捕获异常并且输出结果,提示要输入正确的路径,代码如下:
def test_wrong_path(self):
duplicate_check_function_1("D:\origin.txt","D:\origi.txt")
- 4.本测试向函数中传入两个不同的文本,理论上输出的结果值应该较小,相似度低,代码如下:
def test_diff_file(self):
duplicate_check_function_1("D:\origi.txt","D:\origidif.txt")
- 5.本测试向函数中传入两个相似的文本,理论上结果在0到1之间,并且较为接近1,文本相似度大,代码如下:
def test_sim_file(self):
duplicate_check_function_1("D:\origi.txt","D:\origicopy.txt")
- 6.本测试向函数中传入两个较大的文本,输出比较的结果,代码如下:
def test_long_file(self):
func("D:\orig.txt","D:\orig_0.8_add.txt")
- 7.本测试向函数中传入一个较大的文本和一个较小的文本,输出比较的结果,代码如下:
def test_sl_file(self):
func("D:\orig.txt","D:\origi.txt")
- 8.本测试向函数中传入两个不同类型的文本,输出比较结果,代码如下:
def test_dl_file(self):
func("D:\orig.txt","D:\orig_0.8_dis_1.txt")
- 9.本测试向函数中输入一个空文本和一个有内容的文本,通过捕获异常并输出结果,提示文本错误,要输入正确的文本,代码如下:
def test_eh_file(self):
duplicate_check_function_1("D:\origi.txt","D:\oigiempty.txt")
- 10.本测试向函数中输入一个路径错误文本和一个空文本,通过异常捕获并输出结果,提示文本错误和路径错误,代码如下:
def test_wpe_file(self):
duplicate_check_function_1("D:\oigion.txt","D:\oigiempty.txt")
测试结果
运行并且通过了10个测试,用时1.067s