第二周个人项目作业
1.Github
github链接:https://github.com/lanzero-seven/lany0479
| 这个作业属于哪个班级 | https://edu.cnblogs.com/campus/gdgy/Class56-Grade2024-CS |
|---|---|
| 这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/Class56-Grade2024-CS/homework/15693 |
| 这个作业的目标 | 完成题目为论文查重的个人项目,并对项目使用至少10给用例的单元测试 |
2.PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 10 | 10 |
| · Estimate | · 估计这个任务需要多少时间 | 10 | 10 |
| Development | 开发 | 355 | 299 |
| · Analysis | · 需求分析 (包括学习新技术) | 30 | 32 |
| · Design Spec | · 生成设计文档 | 5 | 7 |
| · Design Review | · 设计复审 | 10 | 5 |
| · Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 10 |
| · Design | · 具体设计 | 20 | 20 |
| · Coding | · 具体编码 | 30 | 25 |
| · Code Review | · 代码复审 | 60 | 30 |
| · Test | · 测试(自我测试,修改代码,提交修改) | 60 | 65 |
| Reporting | 报告 | 60 | 60 |
| · Test Repor | · 测试报告 | 30 | 15 |
| · Size Measurement | · 计算工作量 | 10 | 5 |
| · Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 25 |
| · 合计 | 365 | 309 |
3.计算模块接口的设计与实现过程
3.1 系统整体设计
本项目采用模块化设计思想,将论文查重系统划分为文件读取模块、文本预处理模块、相似度计算模块以及结果输出模块。
3.2 代码组织结构设计
项目主要由以下模块组成:
论文查重系统
├── main.py
│
├── file_io.py
│
├── processing.py
│
├── similarity.py
│
├── tests
│ └── test_similarity.py
│
└── data
(1)main.py —— 程序入口模块
主要负责:
- 命令行参数解析;
- 调用各功能模块;
- 控制程序整体执行流程。
函数关系:
main()
|
├── read_text()
|
├── preprocess_text()
|
├── calc_similarity()
|
└── write_answer()
(2)file_io.py —— 文件输入输出模块
负责文本文件读写。
主要函数为read_text(),负责读取论文文本;write_answer()负责输出查重结果。
设计目的为将文件操作独立出来,使算法模块无需关注文件存储方式。
(3)processing.py —— 文本预处理模块
主要负责:
- 去除无效字符;
- jieba中文分词;
- 停用词过滤。
核心函数为preprocess_text()。具体功能为输入字符串文本,输出词语列表。
(4)similarity.py —— 核心算法模块
该模块用来实现论文查重核心算法。
主要函数如下表:
| 函数 | 功能 |
|---|---|
| calculate_tf() | 计算词频TF |
| calculate_idf() | 计算逆文档频率 |
| calculate_tfidf_vector() | 构建TF-IDF向量 |
| cosine_similarity() | 计算余弦相似度 |
| calc_similarity() | 计算最终重复率 |
3.3 核心算法设计
本项目第一版采用词频统计 + 余弦相似度;优化后采用TF-IDF + 余弦相似度。原因是传统词频方法认为所有词的重要程度相同,容易受到高频无意义词影响。
TF-IDF通过:
来衡量词语在当前文本中的重要程度。
通过:
降低大量出现的普通词权重,提高关键语义词的重要程度。
最终,将文本转换为向量\(V=(w_1,w_2,...,w_n)\);最后利用余弦相似度\(cos(\theta)=\frac{A\cdot B}{|A||B|}\)计算文本相似程度。
做程序流程图如下:

4.计算模块接口部分的性能改进
4.1 优化背景
初始版本采用:直接统计词频并计算余弦相似度。
存在问题:原算法采用words.count(word)需要重复遍历列表。
当文本规模增大时有以下不足:
- 词频统计效率较低;
- 高频词计算重复;
- 时间复杂度较高。
4.2 性能优化过程
(1)词频统计优化
原方法采用list.count(),即每查询一个词,需要遍历整个列表。
优化后,使用collections.Counter进行一次遍历完成词频统计。
复杂度计算为:优化前\(O(n^2)\);优化后\(O(n)\)。
(2)算法优化
将词频向量替换为TF-IDF向量,不仅提高查重准确率,同时减少无意义词对计算结果的影响。
(3)模块化优化
将计算过程拆分为TF计算-->IDF计算-->向量生成-->余弦计算,有效降低了函数复杂度,提高了代码的可维护性。
5.计算模块部分单元测试展示
5.1 测试方法
本项目采用白盒测试方法。针对内部函数逻辑设计测试案例。
测试对象为文件读取函数、文本预处理函数、TF-IDF计算函数、文件输出函数。
5.2 测试案例设计
| 编号 | 测试对象 | 测试内容 | 测试目的 |
|---|---|---|---|
| T1 | read_text | 正常读取txt | 验证文件读取功能 |
| T2 | read_text | 读取不存在文件 | 异常处理 |
| T3 | preprocess_text | 中文分词 | 验证jieba分词 |
| T4 | preprocess_text | 停用词过滤 | 验证文本清洗 |
| T5 | calc_similarity | 完全相同文本 | 验证100%相似 |
| T6 | calc_similarity | 完全不同文本 | 验证低相似度 |
| T7 | calc_similarity | 增加内容 | 验证新增文本影响 |
| T8 | calc_similarity | 删除内容 | 验证删除文本影响 |
| T9 | calc_similarity | 空文本 | 异常输入处理 |
| T10 | write_answer | 正常写入结果 | 验证输出文件 |
5.3 核心代码展示
此处选择单元测试的核心代码进行展示
def test_similarity_same_text():
'''
该测试用于验证两个完全相同文本输入情况下,算法是否能够正确输出100%的重复率。
'''
text=[
"人工智能",
"机器学习"
]
result = calc_similarity(
text,
text
)
assert result == 100
异常测试test_similarity.py
def test_read_text_not_exist():
'''
该函数用来验证系统面对不存在文件路径时,是否能够主动抛出异常。
'''
import pytest
with pytest.raises(FileNotFoundError):
read_text("not_exist.txt")
5.4 测试覆盖率

6.计算模块部分异常处理说明
6.1 文件路径异常
异常设计目标:防止用户输入错误路径导致程序异常退出。
为了处理FileNotFoundError,设计测试test_read_text_not_exist()
使用场景:
输入:wrong_path.txt
程序:主动提示文件不存在。
6.2 空路径异常
异常表现:ValueError
使用场景:用户未输入文件路径。
目的:避免程序继续执行无效读取。
6.3 空文本异常
场景:输入文件为空。
处理:相似度计算函数
if norm1==0:
return 0
从而避免除零错误。
6.4 文件写入异常
场景:输出文件无权限。
处理:捕获PermissionError,从而保证程序不会直接崩溃。
7.心得体会
经过这次作业,我学到了以下知识:
学到了程序与数据分离的思想,及在程序Parameters中引入文件路径参数以完成系统将命令放进sys.argv,从而实现main.py对于数据文本的读取。这样做的好处是,数据路径不定死在代码中,我的代码放到别人的电脑中能够快速调用当前文件下的数据而不用注意代码内的绝对/相对路径读取的限制,从而把代码快速跑通。
根据文件路径读取数据后,数据流动为从orig.txt和orig_add.txt中流进程序read_text,随后进行数据清洗,jieba分词,余弦相似度计算,最后将查重率写入文件ans.txt
学会利用Code Quality Analysis工具的分析并消除所有的警告。据此安装了pylint库,在这期间,学会了如何看pylint的警告信息
并且学会了如何将本地代码利用Git上传到github上面,掌握了一些命令
# 移除已有的origin
git remote remove origin
# 添加新的仓库
git remote add origin https://github.com/lanzero-seven/lany0479.git
# 确认仓库
git remote -v
# 强制执行签入
git push --force
# 提交修改
git add .
# 正式保存更新版本
git commit -m "新的版本名称"
浙公网安备 33010602011771号