这个作业属于哪个课程 | 22计科12班 |
---|---|
作业要求 | 作业 |
github链接 | Github |
作业目标 | 设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率 |
需求分析
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
PSP2.1 | ersonal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10 | 20 |
Estimate | 估计这个任务需要多少时间 | 300 | 200 |
Development | 开发 | 400 | 450 |
Analysis | 需求分析 (包括学习新技术) | 60 | 60 |
Design Spec | 生成设计文档 | 60 | 60 |
Design Review | 设计复审 | 60 | 60 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
Design | 具体设计 | 50 | 60 |
Coding | 具体编码 | 30 | 40 |
Code Review | 代码复审 | 60 | 40 |
Test | 测试(自我测试,修改代码,提交修改) | 10 | 20 |
Reporting | 报告 | 20 | 30 |
Test Report | 测试报告 | 30 | 30 |
Size Measurement | 计算工作量 | 60 | 70 |
Reporting | 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 1210 | 1200 |
原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
从命令行参数给出:论文原文的文件的绝对路径。
从命令行参数给出:抄袭版论文的文件的绝对路径。
从命令行参数给出:输出的答案文件的绝对路径。
我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位
思路分析
可以基于字符串匹配算法比对两篇文章,使用动态规划算法实现,实现较为复杂
使用simHash算法 + 海明距离实现,将高维度特征向量降维,计算海明距离
采用余弦相似度算法,将文章分词后向量化,计算词频向量的夹角余弦值
本次作业项目采用的是第3种方法,通过求余弦相似度来计算文章重复率,实现论文查重
流程分析
使用文件I/O流加载两篇目标文章,读取文章内容
对文章内容进行分词,获得一个个基本分词,便于后续向量化降低维度
采用TFIDF算法来计算两篇文章内容的分词向量,映射在低维空间
计算文本向量的夹角余弦值,得到余弦相似度,并保存在指定文件
解释:
- 处理文章内容函数file_handle
- 内容分词函数segment
- 向量化函数vector_transform
- 计算余弦相似度函数calculate_cos_similarity
- 保存结果到文件函数save_file
文件结构
为对程序功能进行较为全面的评估,采用单元测试的方式进行过功能检验,测试程序代码的健壮性,进行以下一共10个单元测试,从不同角度,不同函数进行测试分析
test_read_empty_file:测试读取空文件
测试读取空文件
def test_read_empty_file(self):
orig_path = ""
orig_add_path = "C:/Users/L/Desktop/3121005134/3121005134/resource/orig_0.8_add.txt"
paperChecked.file_handle(orig_path, orig_add_path)
test_read_notExist_file:测试读取不存在的文件
测试读取不存在的文件
def test_read_notExist_file(self):
orig_path = "C:/Users/L/Desktop/3121005134/3121005134/resource/orig_add.txt"
orig_add_path = "C:/Users/L/Desktop/3121005134/3121005134/resource/orig_0.8_add.txt"
paperChecked.file_handle(orig_path, orig_add_path)
test_filter_dot:测试读取的文件能否过滤标点符号
测试读取的文件能否过滤标点符号
def test_filter_dot(self):
orig_path = "C:/Users/L/Desktop/3121005134/3121005134/resource/orig.txt"
orig_add_path = "C:/Users/L/Desktop/3121005134/3121005134/resource/orig_0.8_add.txt"
orig_file, orig_add_file = paperChecked.file_handle(orig_path, orig_add_path)
print(orig_file, orig_add_file)
test_segment:测试文件内容分词效果
测试文件内容分词效果
def test_segment(self):
orig_path = "C:/Users/L/Desktop/3121005134/3121005134/resource/orig.txt"
orig_add_path = "C:/Users/L/Desktop/3121005134/3121005134/resource/orig_0.8_add.txt"
orig_file, orig_add_file = paperChecked.file_handle(orig_path, orig_add_path)
orig_string, orig_add_string = paperChecked.segment(orig_file, orig_add_file)
print(orig_string, orig_add_string)
test_vectorize:测试分词向量化效果
测试分词向量化效果
def test_vectorize(self):
orig_string = '今天 天气 很好 晴朗 舒适'
orig_add_string = '今日 天气 非常好 晴 愉快'
vector1, vector2 = paperChecked.vector_transform(orig_string, orig_add_string)
print(vector1, vector2)
test_calculate_cos_similarity:测试余弦相似度计算
测试余弦相似度计算
def test_calculate_cos_similarity(self):
vector1 = np.array([1, 2, 3, 4, 5, 6])
vector2 = np.array([1, 2, 3, 4, 5, 6])
similarity = paperChecked.calculate_cos_similarity(vector1, vector2)
print(similarity)
test_save_file:测试输出结果到指定文件中
测试输出结果到指定文件中
def test_save_file(self):
answer_path = "C:/Users/L/Desktop/3121005134/3121005134/resource/answer02.txt"
result = 0.86748569623
similarity = paperChecked.save_file(answer_path, result)
print(similarity)
test_save_not_exist_file:测试输出结果到不存在文件中
测试输出结果到不存在文件中
def test_save_not_exist_file(self):
answer_path = ""
result = 0.86748569623
similarity = paperChecked.save_file(answer_path, result)
print(similarity)
test_result_not_float:测试输出的结果不是浮点型
测试输出的结果不是浮点型
def test_result_not_float(self):
answer_path = "C:/Users/L/Desktop/3121005134/3121005134/resource/answer03.txt"
answer = 2
result = paperChecked.save_file(answer_path, answer)
print(result)
test_paper_check:测试文章查重
测试文章查重
def test_paper_check(self):
main.paper_check()test_result_not_float
性能分析
覆盖率测试
除测试异常代码外的代码覆盖率较高
运行结果
发现均能通过测试
异常处理
文件读取异常 FileNotFoundError
在单元测试test_read_empty_file,test_read_notExist_file,test_save_not_exist_file都有体现
处理文件函数
def file_handle(path1, path2):
try:
# 读取文件内容
with open(path1, 'r', encoding='utf-8') as orig_file, open(path2, 'r', encoding='utf-8') as orig_add_file:
orig_file = orig_file.read()
orig_add_file = orig_add_file.read()
except FileNotFoundError:
print("请输入正确的文件路径")
return FileNotFoundError
# 过滤文件内容的标点符号
dot_str = "\n\r 、,。;:?‘’“”''""!《》,.;:?!<>"
for char in dot_str:
orig_file = orig_file.replace(char, '')
orig_add_file = orig_add_file.replace(char, '')
return orig_file, orig_add_file
结果值非浮点类型异常 ValueError
在单元测试test_result_not_float体现
# 保存结果到文件中,保留两位小数
def save_file(answer_path, answer):
try:
if isinstance(answer, float):
with open(answer_path, 'w') as answer_file:
print('%.2f' % answer, file=answer_file)
return round(answer, 2)
else:
raise ValueError
except ValueError:
print("结果必须是浮点型")
return ValueError
except FileNotFoundError:
print("保存结果的文件不存在")
return FileNotFoundError