第一次个人编程作业

第一次个人编程作业

这个作业属于哪个课程 软件工程
这个作业要求在哪里 第二次作业要求
这个作业的目标 完成个人编程作业编码部分

作业 GitHub 链接:https://github.com/SY-lin123/plagiarism-check/tree/main/3124004476

论文查重

软件工程课程个人项目 —— 基于 TF-IDF 余弦相似度的论文查重工具(Python 3)


一、使用说明

pip install -r requirements.txt
python main.py [原文文件] [抄袭版论文文件] [答案文件]

示例:

python main.py C:\tests\orig.txt C:\tests\orig_add.txt C:\tests\ans.txt

ans.txt 中输出重复率(百分数,保留两位小数,如 85.23)。
若老师要求输出 0~1 的小数,把 main.py 中的 format_rate(rate) 改为 f"{rate:.2f}" 即可。

二、算法设计

模块组织

文件 职责
main.py 命令行入口:解析参数 → 读文件 → 调用查重 → 写答案;统一捕获异常并返回退出码
core.py 核心计算:tokenize() 分词、_tfidf_weights() 加权、similarity() 计算余弦相似度;自定义异常体系

main.main() 是唯一对外接口,core.similarity() 是计算模块唯一被外部调用的函数,耦合度低、便于单元测试。

计算流程

读入两篇文本
    │
    ▼
tokenize()  jieba 精确模式分词,英文统一小写,标点/空白作为分隔符
    │        (jieba 不可用时自动退化为字符 bigram,保证鲁棒性)
    ▼
Counter 统计词频 → 亚线性词频 tf = 1 + ln(count)
    │
    ▼
TF-IDF 加权   idf = ln((1+N)/(1+df)) + 1   (sklearn 平滑形式,N=2)
    │
    ▼
余弦相似度 = Σ(w₁·w₂) / (‖w₁‖·‖w₂‖)   (点积只遍历较小词典,加快速度)
    │
    ▼
×100 保留两位小数 → 写入答案文件

算法关键与独到之处

  1. 亚线性词频 + 平滑 IDF:抑制"的、了"等高频词和超长抄袭段落的支配作用,增删改情形下相似度变化更平滑、更符合直觉。
  2. 鲁棒降级:jieba 未安装时自动切换为字符 bigram(今天是 → 今天/是天/天是/是星/星期/期天/天,),对插入/删除字符依然稳健。
  3. 性能优化:点积遍历时交换两词典保证遍历较小者;Counter + C 实现的 _count_elements 统计词频;13.5 万字文档全流程约 0.18 秒(见 doc/性能分析图.png)。
  4. 异常安全:所有文件/参数/空文档错误均被捕获,按题意空文档输出 0.00 而不崩溃,保证评测程序稳定拿到答案文件。

三、性能分析

使用 cProfile 对 13.5 万字长文档的相似度计算进行剖析(完整数据见 doc/profile.txt):

  • 总耗时 0.178 s,其中 tokenize() 占 0.155 s(87%),是绝对瓶颈;
  • 进一步分解:str.lower() 0.055 s、正则切分 0.040 s、词频统计 0.021 s;
  • 结论:分词为 CPU 密集环节,已通过「仅遍历较小词典」把余弦计算压到 3 ms 以内;如需再提速可关闭 jieba 的 HMM 新词发现(jieba.cut(..., HMM=False)),代价是新词召回略降。

性能分析图:doc/性能分析图.png

四、单元测试

python -m unittest discover -s tests -v          # 运行 15 个测试用例
coverage run --source=core,main -m unittest discover -s tests
coverage report -m                                # 查看分支/语句覆盖率

测试设计(白盒为主,共 15 个用例):

# 用例 覆盖场景
1 相同文本 相似度恒为 1.0(边界)
2 题目样例增删改版 业务正确性,结果 > 0.5
3 完全无关文本 结果趋近 0
4 插入大段新内容 相似度下降但保持较高
5 空字符串 EmptyDocumentError
6 纯空白文档 EmptyDocumentError(tokenize 分支)
7 英文大小写/空格差异 归一化正确性
8 数字与标点 非中文字符不引发异常
9 2 万字长文本 性能回归(< 1 s)
10 格式化边界值 0.0/1.0 → 0.00/100.00
11 越界相似度 ValueError
12 入口正常流程 返回 0,答案符合两位小数格式
13 参数个数错误 返回 2(CliArgumentError 场景)
14 文件不存在 返回 1(FileAccessError 场景)
15 空文件输入 返回 0 且写入 0.00(异常兜底)

五、异常处理说明

异常 设计目标 触发场景(对应测试用例)
CliArgumentError 参数不是 3 个时给出明确提示 用例 13
FileAccessError 文件不存在/不可读时不让程序崩溃 用例 14
EmptyDocumentError 空文档/纯空白文档的明确语义 用例 5、6
兜底策略 抄袭版为空时按 0% 处理并正常写出答案 用例 15

六、PSP 表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 15
Estimate 估计这个任务需要多少时间 20 15
Development 开发 400 545
Analysis 需求分析(包括学习新技术) 60 80
Design Spec 生成设计文档 30 25
Design Review 设计复审(和同事审核设计文档) 20 15
Coding Standard 代码规范(为目前的开发制定合适的规范) 15 10
Coding 具体编码 120 150
Code Review 代码复审 30 35
Test 测试(自我测试,修改代码,提交修改) 125 230
Reporting 报告 110 125
Test Report 测试报告 30 30
Size Measurement 计算工作量 15 10
Postmortem & Process Improvement Plan 事后总结,并提出过程改进计划 65 85
Total 合计 530 685
posted @ 2026-09-15 20:33  linsy-  阅读(8)  评论(0)    收藏  举报