作业二:文本查重

news/2025/3/6 22:04:59/文章来源:https://www.cnblogs.com/Ryon-h/p/18756473

作业介绍

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/SoftwareEngineeringClassof2023
github https://github.com/Ryon-h/3123003446
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/SoftwareEngineeringClassof2023/homework/13324
这个作业的目标 完成文本查重并测试,分析主要算法各函数间关系,性能分析

psp2.1

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

模块接口设计及实现过程

1.该查重系统主要包含以下核心模块接口:

  1. 文件读取模块

    • 接口名: read_file(file_path)
    • 输入:文件路径(字符串)
    • 输出:文件内容(字符串)
    • 功能:读取指定文件的内容,处理可能的编码和IO异常
  2. 相似度计算模块

    • 接口名: calculate_similarity(text1, text2)
    • 输入:两段待比较的文本(字符串)
    • 输出:相似度值(浮点数,范围0-1)
    • 功能:计算两段文本的相似度
  3. 结果保存模块

    • 接口名: save_result(similarity, output_path)
    • 输入:相似度值(浮点数)和输出文件路径(字符串)
    • 输出:无
    • 功能:将相似度结果保存到指定文件

2. 实现过程

  1. 文件读取模块实现
def read_file(file_path):"""读取文件内容"""try:with open(file_path, 'r', encoding='utf-8') as f:return f.read().strip()except Exception as e:print(f'Error reading file {file_path}: {str(e)}')sys.exit(1)

2. 相似度计算模块实现
```python
def calculate_similarity(text1, text2):"""计算两段文本的相似度"""# 使用结巴分词words1 = ' '.join(jieba.cut(text1))words2 = ' '.join(jieba.cut(text2))# 创建TF-IDF向量vectorizer = TfidfVectorizer()tfidf_matrix = vectorizer.fit_transform([words1, words2])# 计算余弦相似度similarity = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:2])[0][0]return similarity

3. 结果保存模块实现
```python
def save_result(similarity, output_path):"""保存查重结果"""try:with open(output_path, 'w', encoding='utf-8') as f:f.write(f'{similarity:.2f}')except Exception as e:print(f'Error writing to file {output_path}: {str(e)}')sys.exit(1)

3. 实现细节说明

  1. 文本预处理 :

    • 使用jieba分词库对中文文本进行分词
    • 将分词结果用空格连接,形成适合TF-IDF处理的格式
  2. 特征提取 :

    • 使用sklearn的TfidfVectorizer进行TF-IDF特征提取
    • 将文本转换为向量形式
  3. 相似度计算 :

    • 使用余弦相似度计算两个文本向量的相似程度
    • 结果范围在0-1之间,越接近1表示越相似
  4. 异常处理 :

    • 对文件读写操作进行异常处理
    • 使用try-except结构捕获可能的错误

4. 使用方法

在命令行中使用以下格式运行程序:

python plagiarism_check.py <原文文件路径> <对比文件路径> <输出文件路径>

该实现采用了模块化设计,各个功能模块之间耦合度低,便于维护和扩展。同时通过合理的异常处理确保了程序的健壮性。##函数之间的关系
### 函数关系说明
1. 主函数 main()- 作为程序入口点- 负责协调其他函数的调用- 调用关系:- 调用 read_file() 两次,分别读取原文和对比文件- 调用 calculate_similarity() 计算相似度- 调用 save_result() 保存结果
2. 文件读取函数 read_file(file_path)- 被 main() 函数调用- 独立执行文件读取操作- 不依赖其他自定义函数- 返回文件内容给 main()
3. 相似度计算函数 calculate_similarity(text1, text2)- 被 main() 函数调用- 依赖外部库函数:- jieba.cut() 进行分词- TfidfVectorizer 进行向量化- cosine_similarity 计算相似度- 返回相似度结果给 main()
4. 结果保存函数 save_result(similarity, output_path)- 被 main() 函数调用- 独立执行文件写入操作- 不依赖其他自定义函数
### 数据流向
1. 文本数据流向:```plaintextread_file() -> main() -> calculate_similarity() -> main() -> save_result()```
  1. 参数传递:

    • main() 从命令行获取文件路径
    • 文件内容通过 read_file() 返回给 main()
    • main() 将文本内容传递给 calculate_similarity()
    • 相似度结果通过 main() 传递给 save_result()

错误处理链

  • 所有函数都实现了错误处理机制
  • 错误发生时通过 sys.exit(1) 终止程序
  • 错误处理顺序:
    1. main() 检查命令行参数
    2. read_file() 处理文件读取错误
    3. save_result() 处理文件写入错误
      这种模块化的设计使得各个函数职责明确,耦合度低,便于维护和测试。主函数作为协调者,统一管理数据流向和函数调用,使程序结构清晰有序。

主要函数分析图

总体算法分析图

算法特点

  1. 分词策略

    • 使用结巴分词(jieba)作为中文分词工具
    • 优势:专门针对中文文本,能准确处理中文词语的切分
    • 相比简单的字符分割,能更好地保留词语的语义信息
  2. TF-IDF向量化

    • 使用 TF-IDF(词频-逆文档频率)进行文本向量化
    • 优势:
      • 不仅考虑词语出现的频率(TF)
      • 还考虑词语的重要性(IDF)
      • 能有效降低常见词的权重,突出关键词的作用
  3. 余弦相似度计算

    • 使用余弦相似度衡量文本相似度
    • 优势:
      • 不受文本长度影响
      • 只关注词语分布的相对比例
      • 结果范围在[0,1]之间,便于理解和使用
  4. 算法特点

    • 高效性:向量化计算,性能好
    • 可扩展性:支持批量文本比较
    • 语言适应性:特别适合中文文本
    • 结果客观:基于数学模型,结果稳定
      这个算法的独到之处在于将中文分词、TF-IDF和余弦相似度三种成熟技术有机结合,既保证了计算的准确性,又兼顾了处理效率。特别适合用于中文论文查重、文本相似度比较等场景。

性能分析

1. 性能分析
首先使用 cProfile 进行性能分析:
import cProfile
import pstats
from plagiarism_check import calculate_similarity# 准备测试数据
with open('test_data.txt', 'r', encoding='utf-8') as f:text1 = f.read()text2 = text1[:int(len(text1)*0.8)]  # 模拟80%相似度的文本# 性能分析
profiler = cProfile.Profile()
profiler.enable()
calculate_similarity(text1, text2)
profiler.disable()# 输出分析结果
stats = pstats.Stats(profiler).sort_stats('cumulative')
stats.print_stats()

``
2. 性能瓶颈分析
性能分析结果显示最耗时的操作:

ncalls  tottime  percall  cumtime  percall filename:lineno(function)1    0.450    0.450    0.450    0.450 jieba.cut1    0.350    0.350    0.350    0.350 vectorizer.fit_transform1    0.200    0.200    0.200    0.200 cosine_similarity
  1. 改进实现
def calculate_similarity(text1, text2):"""计算两段文本的相似度"""# 启用jieba并行处理jieba.enable_parallel(4)# 使用生成器进行分词,减少内存占用words1 = ' '.join(word for word in jieba.cut(text1))words2 = ' '.join(word for word in jieba.cut(text2))# 优化TF-IDF向量化vectorizer = TfidfVectorizer(max_features=5000,  # 限制特征数量dtype=np.float32,   # 使用float32减少内存占用norm='l2',          # 使用L2范数归一化smooth_idf=True     # 平滑IDF权重)# 使用稀疏矩阵存储tfidf_matrix = vectorizer.fit_transform([words1, words2])# 计算余弦相似度similarity = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:2])[0][0]return float(similarity)  # 确保返回Python原生float类型
  1. 性能改进效果
    改进后的性能分析图:
pietitle "优化后的性能分布""jieba分词" : 280"向量化处理" : 220"相似度计算" : 150"其他操作" : 50

性能提升:

  • 分词时间:从450ms降至280ms(↓38%)
  • 向量化时间:从350ms降至220ms(↓37%)
  • 相似度计算:从200ms降至150ms(↓25%)
  • 总体性能提升:约35%

主要改进点:

  1. 并行处理优化

    • 启用jieba并行分词
    • 利用多核CPU优势
  2. 内存优化

    • 使用生成器进行分词
    • 采用float32数据类型
    • 限制特征数量
  3. 算法优化

    • 使用稀疏矩阵存储
    • 优化TF-IDF参数配置
      消耗最大的函数仍然是jieba分词,但其性能已经得到显著提升。建议在实际应用中可以考虑添加分词结果缓存机制,进一步提升性能。

模块部分单元测试展示

import unittest
from plagiarism_check import calculate_similarityclass TestPlagiarismCheck(unittest.TestCase):def test_identical_texts(self):"""测试完全相同的文本"""text = "这是一个测试用例"similarity = calculate_similarity(text, text)self.assertEqual(similarity, 1.0)def test_completely_different_texts(self):"""测试完全不同的文本"""text1 = "今天天气真好"text2 = "学习编程很有趣"similarity = calculate_similarity(text1, text2)self.assertLess(similarity, 0.5)def test_partially_similar_texts(self):"""测试部分相似的文本"""text1 = "我喜欢吃苹果和香蕉"text2 = "我喜欢吃香蕉和橙子"similarity = calculate_similarity(text1, text2)self.assertGreater(similarity, 0.5)self.assertLess(similarity, 1.0)def test_empty_texts(self):"""测试空文本"""text1 = ""text2 = ""similarity = calculate_similarity(text1, text2)self.assertEqual(similarity, 1.0)def test_special_characters(self):"""测试包含特殊字符的文本"""text1 = "测试!@#¥%……&*()"text2 = "测试!@#¥%……&*()"similarity = calculate_similarity(text1, text2)self.assertEqual(similarity, 1.0)if __name__ == '__main__':unittest.main()

测试数据构造思路说明:

  1. 完全相同文本测试 :

    • 验证相同文本的相似度是否为1.0
    • 这是最基本的测试用例
  2. 完全不同文本测试 :

    • 使用语义完全不相关的句子
    • 验证相似度是否较低(小于0.5)
  3. 部分相似文本测试 :

    • 构造部分词语重叠的句子
    • 验证相似度是否在合理范围内(0.5-1.0之间)
  4. 空文本测试 :

    • 测试边界情况
    • 验证程序对空输入的处理
  5. 特殊字符测试 :

    • 测试包含特殊字符的情况
    • 确保程序能正确处理非常规输入

异常处理

先基于原先代码添加异常情况处理代码,其他不变

import unittest
from plagiarism_check import calculate_similarityclass TestPlagiarismCheck(unittest.TestCase):# ... 保持现有测试用例不变 ...def test_none_input(self):"""测试 None 输入"""with self.assertRaises(ValueError):calculate_similarity(None, "测试文本")def test_non_string_input(self):"""测试非字符串输入"""with self.assertRaises(TypeError):calculate_similarity(123, "测试文本")def test_extremely_long_text(self):"""测试超长文本"""long_text = "测试" * 1000000with self.assertRaises(ValueError):calculate_similarity(long_text, "测试文本")

... 保持其他代码不变 ...

查重系统异常处理设计与测试说明

在开发查重系统时,合理的异常处理机制对于系统的健壮性至关重要。本文将详细介绍系统中各类异常的设计目标及其对应的测试用例。

1. 空值(None)输入处理

设计目标

防止系统在接收到 None 值时发生未预期的崩溃,提供清晰的错误提示

def test_none_input(self):"""测试 None 输入"""with self.assertRaises(ValueError):calculate_similarity(None, "测试文本")

应用场景

  • API 调用时传入空值
  • 文件读取失败返回 None
  • 数据预处理过程中的异常情况

2. 类型错误处理

设计目标

确保输入参数类型正确,避免在计算过程中发生类型相关的错误。

测试用例

def test_non_string_input(self):"""测试非字符串输入"""with self.assertRaises(TypeError):calculate_similarity(123, "测试文本")

应用场景

  • 误传入数值类型数据
  • JSON 解析错误导致类型不匹配
  • 外部系统集成时的数据类型不一致

3. 文本长度限制

设计目标

防止系统因处理超大文本而耗尽内存或性能下降。

测试用例

def test_extremely_long_text(self):"""测试超长文本"""long_text = "测试" * 1000000with self.assertRaises(ValueError):calculate_similarity(long_text, "测试文本")

应用场景

  • 用户上传超大文件
  • 爬虫获取的非正常网页内容
  • 恶意请求攻击

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

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

相关文章

上哪儿下载stable diffusion

要在本地环境中下载和安装Stable Diffusion,您可以遵循以下几种方法: 方法一:GitHub源码下载(工作流下载:https://www.mix688.com/964.html)硬件与软件环境准备:确保计算机配备至少4GB显存的NVIDIA GPU。安装Windows操作系统。准备大约10GB的硬盘空间。安装所需软件:下…

清华大学DeepSeek课程:基于DeepSeek的AI音乐词曲创作法(附视频下载)

本课程由清华大学新媒沈阳团队精心打造,旨在教授大家如何利用DeepSeek这一强大的AI工具进行音乐词曲创作。DeepSeek不仅能够帮助我们理解音乐创作的基本原理,还能激发我们的创造力。本课程由清华大学新媒沈阳团队精心打造,旨在教授大家如何利用DeepSeek这一强大的AI工具进行…

2024 年中国大学生程序设计竞赛全国邀请赛(郑州)暨第六届 CCPC 河南省大学生程序设计竞赛(Problem L. Toxel 与 PCPC II)

对于这道题我最开始是想用斜率优化dp,但是x是四次方明显不行,如果是二次方就好了,所以要换一个思路, 可以观察到如果一次性修复的x太多了,会导致时间消耗太大,这样我们还不如一个错误一个错误的修,当x=22时x的四次方就超过了200000,所以说我们最多一次修复22个bug了,值…

2025.3.3微服务架构(Dubbo)

Dubbo配置方式 1.注解: 基于注解可以快速的将程序配置,无需多余的配置信息,包含提供者和消费者。弊端是根据配置信息无法快速定位。XML:和Spring做结合,相关的Service和Reference均使用Spring集成后的。通过这样的方式可以很方便的通过几个文件进行管理整个集群配置。可以快…

数据集蒸馏论文阅读

Dataset Distillation 18年的论文,最早提出数据蒸馏的概念 理论 通常的梯度下降是小批量的 SGD,每次都需要从训练数据中选一个 minibatch 来更新。这篇文章的重点是学习到一个合成数据 \(\hat x=\{\hat x_i\}_{i=1}^M\) 和学习率 \(\hat \eta\),这样我们就可以固定梯度下降的…

数据蒸馏论文阅读

Dataset Distillation 18年的论文,最早提出数据蒸馏的概念 理论 通常的梯度下降是小批量的 SGD,每次都需要从训练数据中选一个 minibatch 来更新。这篇文章的重点是学习到一个合成数据 \(\hat x=\{\hat x_i\}_{i=1}^M\) 和学习率 \(\hat \eta\),这样我们就可以固定梯度下降的…

激活函数汇总

激活函数 激活函数是用来加入非线性因素的,因为线性模型的表达能力不够。 Sigmoid (1) 公式:\(S(x)=\frac{1}{1+e^{-x}}\) (2) 函数图:(3) 缺点: ① 输出值落在(0,1)之间,期望均值为0.5,不符合均值为0的理想状态 ② 该函数存在一正一负两块“死区”(死区:梯度计算为0,…

深入探究C语言内存分配系列函数

深入探究C语言内存分配系列函数 目录深入探究C语言内存分配系列函数内存是什么?内存分配的三种方式为什么要学习动态分配的系列函数?四大内存分配函数前置知识malloc与freemallocfreerealloccallocDeepseek的总结 当我们完成一个程序设计时,需要对其背后的底层原理学习 操作…

第一课 引言与词向量

对于文字的意义,语言学家有很多种定义。其中一种定义运用在自然语言处理中非常有用,这种意义的定义见下分布式语义就是看上下文词来决定单词的意义。于是我们可以利用词向量来衡量两个词之间的相似程度,词的意义被分散在词向量的每一维中 词嵌入之所以叫词嵌入,是因为我们给…

2025.03.06 CW 模拟赛 A. 岛屿

题面 & 题解 A. 岛屿 概率期望会不了一点. 思路 假设我们最开始有 \(a\) 个「蓝蓝 / 红红」链, \(b\)​ 个「蓝红」链. 我们考虑对于每一个「蓝红」链向外连边. 如图, 我们将红点向外连向一条「蓝蓝」链, 由于每一个点只能最多向外连一条边, 那么它们就「合成」了一条蓝蓝链…

日报202535

今天总算是把项目组的事情解决了,于是正式开了Springboot+vue的学习,用了一晚上的时间配置好了环境(更新了JDK与Maven,重新设置了idea的设置) 然后了解了springboot的配置文件和基本使用,跑出了第一个spring的网页。这看着真有意思吧感觉比jsp方便不少。

Java SPI机制使用

1. Service Provider Interface SPI描述接口提供者优先规定接口要求,然后交由具体的实现者对接口进行内容的实现;2. 实现 //1. 定义接口 public Interface Demo_interface{//具体实现者必须要实现的内容void doexcute(); } //2.实现接口 public class Demo_Impl implements D…