软工第一次编程作业:论文查重

news/2024/11/17 14:38:57/文章来源:https://www.cnblogs.com/FFF111/p/18413370

github地址:https://github.com/yingnothing/first.git

个人项目-论文查重

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13229
GitHub链接 https://github.com/yingnothing/first.git
这个作业的目标 实现论文查重算法

需求分析

题目:论文查重

描述如下:

设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。

  • 原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
  • 抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
    要求输入输出采用文件输入输出,规范如下:> >
  • 从命令行参数给出:论文原文的文件的绝对路径。
  • 从命令行参数给出:抄袭版论文的文件的绝对路径。
  • 从命令行参数给出:输出的答案文件的绝对路径。
    我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
    注意:答案文件中输出的答案为浮点型,精确到小数点后两位

PSP表格

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

三、算法与接口设计

流程图

1、接口部分

2、算法分析

1).读取文件

def read_file(file_path):with open(file_path, 'r', encoding='utf-8') as file:return file.read()

read_file函数将读取file_path文件里面的内容并作为返回值返回出去

2).文本预处理

def preprocess(text):text = re.sub(r'[^\w\s]', '', text)  # 去除标点符号words = list(jieba.cut(text))  # 使用 jieba 进行中文分词return words

preprocess函数将对文本进行预处理,实现逻辑如下

text = re.sub(r'[^\w\s]', '', text)

  • 作用: 这是用来去除文本中的标点符号和特殊字符,只保留字母、数字和空白字符(如空格、换行等)。
  • 详细解释:
    • re 是 Python 的正则表达式模块,re.sub() 用于替换匹配到的内容。
    • 正则表达式 r'[^\w\s]'
      • \w:表示匹配所有字母、数字和下划线(a-z, A-Z, 0-9, _),也包括中文字符。
      • \s:表示匹配所有空白字符,包括空格、制表符、换行符等。
      • [^...]:表示取反,匹配除 \w\s 之外的所有字符,也就是标点符号和特殊符号。
    • 替换效果: 将所有标点符号和特殊字符替换为空字符串(即删除它们),只保留字母、数字和空白字符

words = list(jieba.cut(text))

jieba.cut(text)jieba 的分词函数,它会将输入的 text(处理后的中文文本)切分成一个生成器对象,生成器可以迭代出每一个分词结果。

list() 用于将生成器对象转换为一个列表,以便后续使用。

3).统计词的出现次数,生成词频向量

def get_word_frequency_vector(words):# 调用Counterword_freq = Counter(words)return word_freq

计算每个词出现的次数,生成词频向量

4).计算生成的两组词频向量的余弦相似度

def calculate_cosine_similarity(vector1, vector2):# 计算余弦相似度dot_product = sum(vector1[word] * vector2.get(word, 0) for word in vector1)magnitude1 = math.sqrt(sum([count ** 2 for count in vector1.values()]))magnitude2 = math.sqrt(sum([count ** 2 for count in vector2.values()]))if magnitude1 == 0 or magnitude2 == 0:return 0.0return dot_product / (magnitude1 * magnitude2)

通过公式:

计算出余弦相似度

5).将余弦相似度转化为重复率

def calculate_repetition_rate(cosine_similarity):return round(cosine_similarity * 100, 2)

计算重复率,通过round方法四舍五入计算到2位小数

三、性能分析

使用 cProfile 来分析程序性能,记录函数的耗时情况。

表格列的含义:

  1. ncalls:
    • 表示函数被调用的次数。
  2. tottime:
    • 函数本身执行的时间,不包括它调用其他函数所花的时间。这个值用于识别函数自身的性能问题。
  3. percall:
    • tottime / ncalls,即函数每次调用的平均执行时间。
  4. cumtime:
    • 累计时间,表示该函数自身的执行时间加上它调用的所有其他函数的执行时间。
    • 这个值非常有用,可以识别出哪些函数占用了总执行时间的大部分。
  5. filename
    • 该函数的定义位置,包括文件名、行号和函数名称。

表格中的信息按累计时间(cumulative time)排序,从耗时最多的函数开始,帮助识别程序中的性能瓶颈

  1. 最耗时的函数:
    • 表中最上面的函数 preprocess 函数调用了 2 次,但它的累计时间为 1.383 秒,表明这是代码中最耗时的部分。
    • 这也说明了 preprocess 函数是代码的性能瓶颈,处理两个文本的预处理耗费了较多时间。
  2. 细化的耗时函数:
    • cut 函数在文件 __init__.py 第 289 行被调用 11120 次,累计时间为 1.381 秒,几乎占据了 preprocess 的大部分时间。
    • __cut_DAG 这个函数是 cut 的一部分,调用了 10306 次,它的累计时间是 1.374 秒,也很接近总时间,表明这个函数是 cut 内部的一个重要步骤。
  3. 初始化和加载模型:
    • initializemarshal.load 这两个函数分别花费了 1.225 秒1.219 秒,它们是模型加载时的初始化步骤。
    • 模型加载是处理文本的一部分,这些函数只执行一次,但耗时较多。

结论:

  • 程序中的性能瓶颈主要在 文本预处理(preprocess),特别是在使用 jieba 库进行分词时。
  • cut__cut_DAG 是最耗时的操作,它们在分词过程中被频繁调用。优化这些部分可能会显著改善性能。
  • 模型初始化 (initializemarshal.load) 的时间也比较长(大约 1.2 秒)。这是加载分词模型时的开销,虽然只发生一次,但对总执行时间影响较大。

可以进行的优化:
缓存分词结果:如果文本较大,可以考虑对分词结果进行缓存,避免每次处理文本都重新加载模型并进行分词。
并行化:在处理大量文本时,可以考虑使用多线程或多进程来并行处理文本,减少单次分词的时间消耗。
模型预加载:如果分词模型加载时间较长,可以在程序启动时预先加载模型,减少后续分词过程中的加载时间。

四、异常处理:

def read_file(file_path):try:with open(file_path, 'r', encoding='utf-8') as file:return file.read()except Exception as e:print(f"Error reading file: {str(e)}")sys.exit(1)

当读取文件的路径不存在时则会捕获异常并退出程序

def write_output(file_path, result):try:# 提取目录路径directory = os.path.dirname(file_path)# 如果目录不存在,则创建目录if directory and not os.path.exists(directory):os.makedirs(directory, exist_ok=True)# 尝试写入结果到文件with open(file_path, 'w', encoding='utf-8') as file:file.write(f"{result}%")except OSError as e:# 捕获由于无效路径或文件名导致的错误print(f"Error: Could not write to file '{file_path}'. Reason: {str(e)}")sys.exit(1)

当作为存取输出的文件不存在时会自动创建文件,如果路径错误则会捕获异常并退出程序

五、测试代码覆盖率

使用 Python 的 unittest 模块进行单元测试,具体代码在github上面,这里只放测试结果


通过对preprocess,get_word_frequency_vector,calculate_cosine_similarity,calculate_repetition_rate函数进行测试,其中calculate_cosine_similarity函数要注意测试余弦值等于0的情况。如图所示结果符合预期,且代码覆盖率达到100%
最后:
生成 HTML 格式的覆盖率报告:

代码无任何错误或警告

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/797252.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

个人项目——论文查重

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13229这个作业的目标 个人项目——论文查重一:我的github仓库地址 https://github.com/kelin-KL/kelin-KL 二:PSP表格…

OI海海

在pyq里看到了殿禾Wrose的“X的随波逐流”,附文是“我与OI的365天”,我才想到,我打OI也整整一年了 有人或许不理解我这样的一个蒟蒻为什么这么喜欢喜欢写怀念类的东西,即使到现在我还没有取得任何的奖项以及未来也并没有概率拿牌 因为我只觉得一步步走来,不记得的话,是很…

GIS可视化软件:地理信息与遥感领域中的洞察之眼

在地理信息与遥感技术的广阔天地中,可视化软件如同一双洞察世界的明眸,将复杂的数据编织成生动、直观的画卷,为我们揭示地球的奥秘与城市的律动。本文将深入挖掘其技术核心、应用实例、未来趋势,探讨可视化软件如何为地理信息与遥感技术带来深刻洞见。 可视化软件的核心与技…

USB分析仪USB3.2日志分析

1.简介 USB2.0总线采用轮询模式,即总线事务开始时,都要先发送IN或者OUT令牌包,以通知端点或者查询端点是否准备好。而USB3.2采用了异步通知模式,若端点没有准备好,则主机无需轮询,端点准备好后会通知主机,而对于OUT端点,主机会直接发送DP数据包,相当于将USB2.0中的OUT…

[第一章 web入门]SQL注入-1

启动靶机很明显注入点为id值,单引号闭合影响语句,说明为单引号闭合构造注入语句 ?id=1 and 1 =1 --+ 发现没报错,说明没有其他过滤 ,开始sql注入 ?id=1 order by 4 --+ 直到=4报错说明有3个字节段测试回显位2,3 ?id=1 and 1 = 2 union select 1,2,3 --+ 测试当…

数据结构 —堆

今天学习算法了没,你小子瞅啥呢!一:堆 1、一种二叉树的结构(完全二叉树) 2、完全二叉树:从上到下;从左到右;填满 3、最大堆:根节点的权值大于孩子节点 4、最小堆:根节点的权值依次小于孩子节点 5、常用操作 import heapq# 创建最小堆和最大堆 min_heap = [] max_heap…

软工第一次作业-论文查重

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13229这个作业的目标 通过Java开发个人项目,实现项目单元测试作业github地址(含jar包) github:https://github.com/…

第二十讲:为什么我只改一行的语句,锁这么多?

该文章深刻揭示了一点:加索引=行锁+间隙锁=(next-key lock),分析了加锁的规则:对主键(唯一索引),普通非唯一索引进行等值与范围查询的加锁。这篇文章我认为收获最大的是让我们知道“明明对一行加了锁,为什么在他相邻部分,或是相相邻部分无法插入数据(这根主键类型,…

【视频讲解】线性时间序列原理及混合ARIMA-LSTM神经网络模型预测股票收盘价研究实例

原文链接:https://tecdat.cn/?p=37702 原文出处:拓端数据部落公众号 分析师:Dongzhi Zhang 近年来人工神经网络被学者们应用十分广泛,预测领域随着神经网络的引入得到了很大的发展。本文认为单一神经网络模型对序列所包含的线性信息和非线性信息的挖掘是有限的,因此本…

Docker-Compose搭建RustDesk服务器

前置条件:电脑安装RustDesk客户端,服务器安装Docker及docker-compose官方文档:安装 :: RustDesk文档操作流程:使用Vim编写docker-compose.yml文件,修改需要的端口,最好按照官方对应的端口来操作,< >内替换成服务器对外的端口。记住挂载文件路径,容器运行后会生成密…

CMake构建学习笔记16-使用VS进行CMake项目的开发

详细介绍了通过Visual Studio 2019 这款IDE进行CMake项目开发过程,能够极大增加C/C++程序的开发效率。目录1. 概论2. 详论2.1 创建工程2.2 加载工程2.3 配置文件2.4 工程配置2.5 调试执行3. 项目案例4. 总结 1. 概论 在之前的系列博文中,我们学习了如何构建第三方的依赖库,也…