个人项目刘恒君

个人项目 论文查重

软件工程  首页 - 计科国际班 - 广东工业大学 - 班级博客 - 博客园 (cnblogs.com)
作业要求 个人项目 - 作业 - 计科国际班 - 班级博客 - 博客园 (cnblogs.com)
 作业目标  代码实现,性能分析,单元测试,异常处理说明,记录PSP表格

设计代码上传GitHub仓库:刘恒军字/3119009438 (github.com)

PSP表格:

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning 计划 120 150
· Estimate · 估计这个任务需要多少时间 120 150
Development 开发 480 300
· Analysis · 需求分析 (包括学习新技术) 120 100
· Design Spec · 生成设计文档 30 10
· Design Review · 设计复审 30 10
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 5
· Design · 具体设计 10 5
· Coding · 具体编码 120 120
· Code Review · 代码复审 20 5
· Test · 测试(自我测试,修改代码,提交修改) 20 20
Reporting 报告 30 20
· Test Repor · 测试报告 20 10
· Size Measurement · 计算工作量 5 5
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 5 5
Total 总计 1150 915

 

使用的接口:

jieba.cut  

用于对中文句子进行分词,功能非常强大

jieba库分词的三种模式:
  1、精准模式:把文本精准地分开,不存在冗余
  2、全模式:把文中所有可能的词语都扫描出来,存在冗余
  3、搜索引擎模式:在精准模式的基础上,再次对长词进行切分

这里我们使用精准模式

re.match

由于对比对象为中文或英文单词,因此应该对读取到的文件数据中存在的换行符\n、标点符号过滤掉,这里选择用正则表达式来匹配符合的数据

代码:def filter(str):

str = jieba.lcut(str) result = []

for tags in str:

if (re.match(u"[a-zA-Z0-9\u4e00-\u9fa5]", tags)):

result.append(tags)

else: pass

return result

 这里正则表达式为u"[a-zA-Z0-9\u4e00-\u9fa5]",也即对jieba.cut分词之后的列表中的值,只保留英文a-zA-z、数字0-9和中文\u4e00-\u9fa5的结果。

gensim.dictionary.doc2bow

Doc2Bow是gensim中封装的一个方法,主要用于实现Bow模型。

Bag-of-words model (BoW model) 最早出现在自然语言处理(Natural Language Processing)和信息检索(Information Retrieval)领域.。该模型忽略掉文本的语法和语序等要素,将其仅仅看作是若干个词汇的集合,文档中每个单词的出现都是独立的。

gensim.similarities.Similarity

该方法可以用计算余弦相似度,但具体的实现方式官网似乎并未说清楚,这是我查找大量文章得到的一种实现方式:

from math import sqrt
def similarity_with_2_sents(vec1, vec2):
inner_product = 0
square_length_vec1 = 0
square_length_vec2 = 0
for tup1, tup2 in zip(vec1, vec2):
inner_product += tup1[1]*tup2[1]
square_length_vec1 += tup1[1]**2
square_length_vec2 += tup2[1]**2

return (inner_product/sqrt(square_length_vec1*square_length_vec2))


cosine_sim = similarity_with_2_sents(vec1, vec2)
print('两个句子的余弦相似度为: %.4f。'%cosine_sim)

代码实现

import jieba
import gensim
import re

#获取指定路径的文件内容
def get_file_contents(path):
str = ''
f = open(path, 'r', encoding='UTF-8')
line = f.readline()
while line:
str = str + line
line = f.readline()
f.close()
return str

#将读取到的文件内容先进行jieba分词,然后再把标点符号、转义符号等特殊符号过滤掉
def filter(str):
str = jieba.lcut(str)
result = []
for tags in str:
if (re.match(u"[a-zA-Z0-9\u4e00-\u9fa5]", tags)):
result.append(tags)
else:
pass
return result

#传入过滤之后的数据,通过调用gensim.similarities.Similarity计算余弦相似度
def calc_similarity(text1,text2):
texts=[text1,text2]
dictionary = gensim.corpora.Dictionary(texts)
corpus = [dictionary.doc2bow(text) for text in texts]
similarity = gensim.similarities.Similarity('-Similarity-index', corpus, num_features=len(dictionary))
test_corpus_1 = dictionary.doc2bow(text1)
cosine_sim = similarity[test_corpus_1][1]
return cosine_sim

if __name__ == '__main__':
path1 = "D:\PycharmProjects\orig.txt" #论文原文的文件的绝对路径(作业要求)
path2 = "D:\PycharmProjects\orig_0.8_add.txt" #抄袭版论文的文件的绝对路径
save_path = "D\PycharmProjects\save.txt" #输出结果绝对路径
str1 = get_file_contents(path1)
str2 = get_file_contents(path2)
text1 = filter(str1)
text2 = filter(str2)
similarity = calc_similarity(text1, text2)
print("文章相似度: %.4f"%similarity)
#将相似度结果写入指定文件
f = open(save_path, 'w', encoding="utf-8")
f.write("文章相似度: %.4f"%similarity)
f.close()

 运行结果:![image-20210921165654278](C:\Users\Liu\AppData\Roaming\Typora\typora-user-images\image-20210921165654278.png)

更改路径后:

 path1 = "D:\PycharmProjects\orig.txt" ##论文原文的文件的绝对路径

path2 = "D:\PycharmProjects\orig_0.8_dis_10.txt" #抄袭版论文的文件的绝对路径

运行结果:![image-20210921170815524](C:\Users\Liu\AppData\Roaming\Typora\typora-user-images\image-20210921170815524.png)

 

性能分析

利用pycharm的插件可以得到耗费时间的几个主要函数排名:

 ![image-20210921171247081](C:\Users\Liu\AppData\Roaming\Typora\typora-user-images\image-20210921171247081.png)

 

关注到filter函数:由于cutlcut暂时找不到可提到的其他方法(jieba库已经算很强大了),暂时没办法进行改进,因此考虑对正则表达式匹配改进。

这里是先用lcut处理后再进行匹配过滤,这样做显得过于臃肿,可以考虑先匹配过滤之后再用lcut来处理

改进代码:

def filter(string):
pattern = re.compile(u"[^a-zA-Z0-9\u4e00-\u9fa5]")
string = pattern.sub("", string)
result = jieba.lcut(string)
return result

结果:![image-20210921171501352](C:\Users\Liu\AppData\Roaming\Typora\typora-user-images\image-20210921171501352.png)

可以看到总耗时快了0.5s,提升了时间效率

代码覆盖率

几乎百分之一百,满足要求:

![image-20210921171903612](C:\Users\Liu\AppData\Roaming\Typora\typora-user-images\image-20210921171903612.png)

单元测试

import jieba
import gensim
import re

#获取指定路径的文件内容
def get_file_contents(path):
string = ''
f = open(path, 'r', encoding='UTF-8')
line = f.readline()
while line:
string = string + line
line = f.readline()
f.close()
return string

#将读取到的文件内容先把标点符号、转义符号等特殊符号过滤掉,然后再进行结巴分词
def filter(string):
pattern = re.compile(u"[^a-zA-Z0-9\u4e00-\u9fa5]")
string = pattern.sub("", string)
result = jieba.lcut(string)
return result

#传入过滤之后的数据,通过调用gensim.similarities.Similarity计算余弦相似度
def calc_similarity(text1, text2):
texts = [text1, text2]
dictionary = gensim.corpora.Dictionary(texts)
corpus = [dictionary.doc2bow(text) for text in texts]
similarity = gensim.similarities.Similarity('-Similarity-index', corpus, num_features=len(dictionary))
test_corpus_1 = dictionary.doc2bow(text1)
cosine_sim = similarity[test_corpus_1][1]
return cosine_sim


def main_test():
path1 = input("输入论文原文的文件的绝对路径:")
path2 = input("输入抄袭版论文的文件的绝对路径:")
str1 = get_file_contents(path1)
str2 = get_file_contents(path2)
text1 = filter(str1)
text2 = filter(str2)
similarity = calc_similarity(text1, text2) #生成的similarity变量类型为<class 'numpy.float32'>
result=round(similarity.item(),2) #借助similarity.item()转化为<class 'float'>,然后再取小数点后两位
return result


if __name__ == '__main__':
main_test()

为了使预期值更好确定,这里考虑只取返回的相似度值的前两位,借助round(float,2)即可处理,由于生成的similarity类型为<class 'numpy.float32'>,因此应当先转化为<class 'float'>,查找对应解决方法:通过xxx.item()即可转化。

再新建单元测试文件unit_test.py:

import unittest
from main import main_test


class MyTestCase(unittest.TestCase):
def test_something(self):
self.assertEqual(main_test(),0.99) #首先假设预测的是前面第一组运行的测试数据


if __name__ == '__main__':
unittest.main()

 

可以发现预测值为0.99正确:

 

异常处理说明

在读取指定文件路径时,如果文件路径不存在,程序将会出现异常,因此可以在读取指定文件内容之前先判断文件是否存在,若不存在则做出响应并且结束程序。

这里引入os.path.exists()方法用于检验文件是否存在:


def main_test():
path1 = input("输入论文原文的文件的绝对路径:")
path2 = input("输入抄袭版论文的文件的绝对路径:")
if not os.path.exists(path1) :
print("论文原文文件不存在!")
exit()
if not os.path.exists(path2):
print("抄袭版论文文件不存在!")
exit()
······

posted @ 2021-09-21 17:28  计科1班刘恒君  阅读(46)  评论(0编辑  收藏  举报