第一次个人项目作业
这个作业属于哪个课程 | 班级的链接 |
---|---|
这个作业要求在哪里 | 作业要求的链接 |
这个作业的目标 | 设计论文查重算法并开发,用PSP表格记录 |
Github | https://github.com/Altriaaaa/3119005433 |
实现思路
网上信息收集可以知道,实现论文查重有多重算法思路,本人使用余弦定理,当然欧式距离,海明距离也是可以的。
需要def的函数:open_file_read,cut,caculate_similarity,main
整体思路为:
首先通过open_file_read函数,把要原文和要查重的文章读入程序。过滤掉各种标点符号和换行,只匹配英文数字和汉字,生成字符串。得到的字符串用jieba库的lcut函数来分词,生成一个list。接着调用gensim,创建语料库,用doc2bow实现bow模型,计算两个向量的余弦相似度,即可得到两篇文章的相似度,最后把相似度写进answer文本里面。
接口分析
jieba.cut
可以兼容中文句子进行分词,此处用精确模式即可,详细功能见Github
import jieba
sent = "我是谭清允,我就读于广东工业大学"
print(jieba.lcut(sent))
# ['我', '是', '谭清允', ',', '我', '就读于', '广东', '工业', '大学']
re.match
因为文章里面有中文,英文,各种标点符号和换行符,所以要用re模块的match正则匹配换行符和标点符号。\W匹配除了字母,数字,下划线之外的字符,匹配到就替换为空。
import jieba
import re
sent = "我是谭清允,我就读。!‘于广东工业大学。,"
cut = jieba.lcut(sent)
res = []
for word in cut:
if (re.match(u"[\W+]", word)):
res.append(word)
else:
pass
print (res)
# [',', '。', '!', '‘', '。', ',']
gensim.dictionary.doc2bow
Doc2Bow是gensim中封装的一个方法,主要用于实现Bow模型。原理参考文章
首先给出两个简单的文本文档如下:
John likes to watch movies. Mary likes too.
John also likes to watch football games.
基于上述两个文档中出现的单词,构建如下一个词典 (dictionary):
{"John": 1, "likes": 2,"to": 3, "watch": 4, "movies": 5,"also": 6, "football": 7, "games": 8,"Mary": 9, "too": 10}
上面的词典中包含10个单词, 每个单词有唯一的索引, 那么每个文本我们可以使用一个10维的向量来表示。如下:
[1, 2, 1, 1, 1, 0, 0, 0, 1, 1]
[1, 1,1, 1, 0, 1, 1, 1, 0, 0]
该向量与原来文本中单词出现的顺序没有关系,而是词典中每个单词在文本中出现的频率。
也是通过余弦定理计算两个句子的相似度。
def caculate_similarity(cut_first_text, cut_second_text):
texts = [cut_first_text, cut_second_text]
# 创建语料库
repository = gensim.corpora.Dictionary(texts)
# doc2bow
corpus = [repository.doc2bow(text) for text in texts]
# num_features代表生成的向量的维数(根据词袋的大小来定)
cosine_similarity = gensim.similarities.Similarity('-Similarity-index', corpus, num_features=len(repository))
# 获取句子相似度
testing_corpus = repository.doc2bow(cut_first_text)
cosine_similarity = cosine_similarity[testing_corpus][1]
return cosine_similarity
代码实现
代码部分
import re
import gensim
import jieba
import sys
# 打开文件并读取内容
def open_file_read(path):
text = ''
file = open(path, 'r', encoding='UTF-8')
each_line = file.readline()
while each_line:
text += each_line
each_line = file.readline()
# 使用re模块的sub()实现正则匹配,替换标点符号为空
# \W匹配除了字母,数字,下划线之外的字符
final_text = re.sub('\W+', '', text).replace("_", '')
file.close()
return final_text
def cut(final_text):
res = jieba.lcut(final_text)
return res
def caculate_similarity(cut_first_text, cut_second_text):
texts = [cut_first_text, cut_second_text]
# 创建语料库
repository = gensim.corpora.Dictionary(texts)
# doc2bow
corpus = [repository.doc2bow(text) for text in texts]
# num_features代表生成的向量的维数(根据词袋的大小来定)
cosine_similarity = gensim.similarities.Similarity('-Similarity-index', corpus, num_features=len(repository))
# 获取句子相似度
testing_corpus = repository.doc2bow(cut_first_text)
cosine_similarity = cosine_similarity[testing_corpus][1]
return cosine_similarity
def main():
try:
first_path = sys.argv[1]
second_path = sys.argv[2]
answer = sys.argv[3]
first_text = open_file_read(first_path)
second_text = open_file_read(second_path)
cut_first_text = cut(first_text)
cut_second_text = cut(second_text)
cosine_similarity = caculate_similarity(cut_first_text, cut_second_text)
print("cosine_similarity is %.2f" % cosine_similarity)
answer_file = open(answer, 'w', encoding="utf-8")
answer_file.write("cosine_similarity is %.2f" % cosine_similarity)
answer_file.close()
except Exception as e:
print(e)
exit("请使用命令行传参,格式如python main.py [原文文件] [抄袭版论文的文件] [答案文件]")
def test_main():
first_path='C:\\Users\\84330\\Desktop\\3119005433-main\\测试文本2\\orig.txt'
second_path='C:\\Users\\84330\\Desktop\\3119005433-main\\测试文本2\\orig_0.8_add.txt'
first_text = open_file_read(first_path)
second_text = open_file_read(second_path)
cut_first_text = cut(first_text)
cut_second_text = cut(second_text)
cosine_similarity = caculate_similarity(cut_first_text, cut_second_text)
cosine_similarity = round(cosine_similarity.item(), 2)
return cosine_similarity
if __name__ == '__main__':
main()
运行结果
两篇文章相似度高达99%,可以实现查重任务的准确性。
单元测试
用到python的unittest单元测试框架
代码部分
import unittest
from main import *
class MyTestCase(unittest.TestCase):
def testing(self):
self.assertEqual(test_main(), 0.99)
if __name__ == '__main__':
unittest.main()
运行结果
可以看到相似度校验通过
性能分析
代码覆盖率
main.py的代码覆盖率100%,达到要求。
except Exception as e:
print(e)
exit("请使用命令行传参,格式如python main.py [原文文件] [抄袭版论文的文件] [答案文件]")
耗费的时间
符合题目5秒内给出答案,能完成查重任务。
异常处理
如果没有用命令行传参,会显示错误信息并提示用命令行传参
PSP表格
*PSP2.1* | *Personal Software Process Stages* | *预估耗时(分钟)* | *实际耗时(分钟)* |
---|---|---|---|
Planning | 计划 | 30 | 30 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 30 |
Development | 开发 | 410 | 490 |
· Analysis | · 需求分析 (包括学习新技术) | 120 | 150 |
· Design Spec | · 生成设计文档 | 30 | 30 |
· Design Review | · 设计复审 | 40 | 50 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 20 |
· Design | · 具体设计 | 60 | 60 |
· Coding | · 具体编码 | 100 | 150 |
· Code Review | · 代码复审 | 30 | 30 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 60 |
Reporting | 报告 | 30 | 30 |
· Test Repor | · 测试报告 | 20 | 20 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 40 |
· 合计 | 590 | 750 |