第一次个人编程作业
作业课程 | 软件工程 |
---|---|
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。 | |
需求分析
题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
- 原文实例:今天是星期天,天气晴,今天晚上我要去看电影。
- 抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
- 从命令行参数给出:论文原文的文件的绝对路径。
- 从命令行参数给出:抄袭版论文的文件的绝对路径。
- 从命令行参数给出:输出的答案文件的绝对路径。
我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位。
接口设计与实现过程
设计思路
- 读取文件:从命令行参数获取原文文件和抄袭版论文文件的路径,使用Python的文件操作方法打开并读取两个文件。
- 文本预处理:对原文和抄袭版论文进行预处理,过滤文件内容的标点符号。
- 分词:将原文和抄袭版论文进行分词,使用Python的jieba分词库,对文本进行分词处理,获得一个个基本分词,便于后续向量化降低维度。
- 向量化:用TFIDF算法来计算两篇文章内容的分词向量,映射在低维空间。
- 计算相似度:采用余弦相似度算法,将文章分词后向量化,使用scikit-learn库实现向量化,得到余弦相似度,并保存在指定文件。
- 输出结果:将计算得到的重复率写入输出答案文件。
接口设计
- 处理文件函数,过滤文件内容的标点符号。
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("Please enter the correct file path!")
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
- 分词函数,使用jieba库分词将文件内容分词,空格分隔关键词
def segment(orig_file, orig_add_file):
orig_string = ' '.join(jb.lcut(orig_file))
orig_add_string = ' '.join(jb.lcut(orig_add_file))
return orig_string, orig_add_string
- 向量化,将分词内容转换为向量,使用TFIDF算法。
def vector_transform(orig_string, orig_add_string):
tfidf_vec = TfidfVectorizer()
text = [orig_string, orig_add_string]
features = tfidf_vec.fit_transform(text).toarray()
return features[0], features[1]
- 计算余弦相似度,计算两个向量的余弦相似度。
def calculate_cos_similarity(vector1, vector2):
dot = sum(vector1[i] * vector2[i] for i in range(len(vector1)))
norm1 = math.sqrt(sum(pow(i, 2) for i in vector1))
norm2 = math.sqrt(sum(pow(i, 2) for i in vector2))
similarity = dot / (norm1 * norm2)
return similarity
- 保存结果,将结果保存到文件中。
def save_file(answer_path, result):
try:
if isinstance(result, float):
with open(answer_path, 'w') as answer_file:
print('%.2f' % result, file=answer_file)
return round(result, 2)
else:
raise ValueError
except ValueError:
print("The result must be a floating-point type!")
return ValueError
except FileNotFoundError:
print("The file that saved the results does not exist!")
return FileNotFoundError
实现过程
依据设计思路,一共六步,分别是读取文件内容、文本预处理、内容分词、向量化函数、计算文本之间的余弦相似度、保存结果,每一步实现一个函数功能,封装到paper_check.py中,在main.py用paper_checked函数顺序调用paper_check.py中的功能函数,组合实现论文查重功能。
接口部分的性能改进
图中展示函数之间的调用关系、调用次数和执行时间等信息,查重过程中用于进行余弦相似度计算的两个函数和用于分词处理的函数运行时间占了程序总执行时间的大部分,该部分为整个程序的主体部分。由于文章进行分词的过程由文章长度和构成所决定的,无法在性能上进一步优化。
模块部分单元测试展示
测试结果
图中展示10个测试通过的总耗时818ms,文章查重测试为696ms,分词消耗112ms。大部分时间用在文章查重和分词消耗。
模块部分异常值处理
- 处理函数文件
file_handle
如果文件读取异常,则FileNotFoundError。 - 保存结果
save_file
如果出现值非浮点型异常,则ValueError。
附录 PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
· Estimate | · 估计这个任务需要多少时间 | ||
· Analysis | · 需求分析 (包括学习新技术) | ||
· Design Spec | · 生成设计文档 | ||
· Design Review | · 设计复审 | ||
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | ||
· Design | · 具体设计 | ||
· Coding | · 具体编码 | ||
· Code Review | · 代码复审 | ||
· Test | · 测试(自我测试,修改代码,提交修改) | ||
· Test Repor | · 测试报告 | ||
· Size Measurement | · 计算工作量 | ||
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | ||
· 合计 |