zoukankan      html  css  js  c++  java
  • 个人项目:论文查重

    这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Networkengineering1834
    这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Networkengineering1834/homework/11146
    这个作业的目标 学会使用PSP表格规划项目开发计划,学习使用Git管理代码,Markdown 基础语法编写文本,学习写博客,学习文本相似度计算算法

    GitHub 仓库地址

    https://github.com/Boyle-Coffee/3118005327

    PSP表格

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

    算法设计

    算法思路

    本算法采用 SimHash 值来计算段落的局部敏感哈希值,先采用 jieba 框架提取两篇论文的关键字及其权重,并根据关键字以及权重分别计算两篇论文各个段落的哈希值,并计算各个段落间的哈希值的海明距离,形成相似矩阵,根据相似矩阵以及设定好的阈值,来确定哪些段落比较相似,进而计算出待查论文与原论文的相似度。

    SimHash 算法主要参考博客:simhash算法

    代码主要参考GitHub库:https://github.com/CuiYongen/DuplicateChecking

    算法流程图

    接口设计与实现过程

    接口及功能的具体设计

    该项目主要包括两个模块,文件管理模块与计算模块,文件管理模块主要负责读取与存储文件,计算模块主要负责计算文字的局部敏感哈希值以及论文的重复率,各模块接口的具体设计如下:

    文件管理模块方法

    file_util.load_file:

    功能:加载txt文件内容

    输入参数:

    • file_path:读取txt文件的路径

    返回值:

    • parags:文件内容,即包含txt文件的字符序列的列表

    file_util.save_file:

    功能:保存文件内容,本项目将保存论文的重复率以及相似的段落

    输入参数:

    • file_path:文件路径
    • result:文件内容,即论文查重算法的结果

    返回值:

    计算模块方法

    cal_util.cal_repeat_rate

    功能:采用SimHash算法计算论文的重复率,供主模块调用的方法,是该模块的主方法

    输入参数:

    • orig_paper:原论文的字符序列
    • orig_modify_paper:抄袭论文的字符序列

    返回值:

    • result:保留计算结果的字典,包括两篇论文的重复率和重复的段落;当返回 -1 时,说明抄袭论文编码读取失败;当返回 -2 时,说明原论文编码读取失败;返回 -3 则是计算汉明距离时发生错误

    项目结构体系

    类调用关系

    该项目的主函数为 main.py 函数,它负责解析命令行,并根据命令行的参数,调用 file_util 模块的接口读取文件,再调用 cal_util 的方法计算论文的重复率,最后调用 file_util 模块的接口保存结果

    计算模块方法的改进

    主要改进了方法 cal_util.cal_repeat_rate ,原本的计算方式是利用内外两层 for 循环来分别计算原论文与待查论文各段落的相似度,伪代码如下:

    for para_a in ori_paper:
    	for para_b in ori_add_paper:
    		conter_dis(para_a, para_b)
    

    当这样的计算效率低下,测试1中所用的时间高达33秒,所以我改进了算法,采用两个并列的 for 循环分别计算SimHash,并将结果保存在两个数组中,最后利用 NumPy 的矩阵运算计算相似度矩阵,加快运行速度,计算相似度,伪代码如下:

    a_list = []
    for para_a in ori_paper:
    	a_list.append(simhash(para_a))
    b_list = []
    for para_b in ori_add_paper:
    	b_list.append(simhash(para_b))
    conter_dis_with_numpy_mat(a_list, b_list)  # 利用 NumPy 的矩阵运算计算相似度矩阵
    

    这样的改进,测试1所用时间为0.388秒,速度提升了将近一百倍。

    计算模块部分异常处理说明

    对于计算不同部分的错误,通过返回不同数值的负数来反馈,当 cal_util.cal_repeat_rate 返回的值不是字典,而是负值时,说明计算过程中出现异常,这里采用伪代码表述:

    def cal_repeat_rate(orig_paper, orig_modif_paper):
        try:
            cal_hash(orig_paper)  # 计算原论文哈希值
        except:
            return -1
        
        try:
            cal_hash(orig_modify_paper)  # 计算待查论文哈希值
        except:
            return -2
        
        try:
            cal_hamming_dis()  # 计算海明距离
            result = save_sim_parag()  # 保存计算结果
        except:
            return -3
        return result
    

    可以看到,当返回 -1 时,说明抄袭论文编码读取失败;当返回 -2 时,说明原论文编码读取失败;返回 -3 则是计算汉明距离或者保存计算结果时发生错误,这样外部接收到返回值后,就能及时知道是哪里出现错误。

    计算模块部分单元测试展示

    测试一

    测试内容:输入正常txt文件 orig_0.8_add.txt 的路径

    输入:

    # 在项目根目录输入命令行
    $ python main.py dataset/orig.txt dataset/orig_0.8_add.txt dataset/ans.txt
    

    结果:

    成功计算出重复率,并将结果保存到 ans.txt 文件中,耗时大约 0.388s , 部分结果如下:

    测试二

    测试内容:当输入的原论文文件不存在时,进行测试

    输入:

    # 在项目根目录输入命令行
    $ python main.py dataset/not_exist.txt dataset/orig_0.8_add.txt dataset/ans.txt
    

    结果:

    提示文件不存在,并打印一下错误内容

    测试三

    测试内容:当输入的待查论文文件不存在时,进行测试

    输入:

    # 在项目根目录输入命令行
    $ python main.py dataset/orig.txt dataset/not_exist.txt dataset/ans.txt
    

    结果:

    提示文件不存在,并打印一下错误内容

    测试四

    测试内容:输入正常txt文件 orig_0.8_add.txt 的路径

    输入:

    # 在项目根目录输入命令行
    $ python main.py dataset/orig.txt dataset/orig_0.8_del.txt dataset/ans2.txt
    

    结果:

    成功计算出重复率,并将结果保存到 ans2.txt 文件中,耗时大约 0.348s,部分结果如下:

    测试五

    测试内容:当输入的原论文文件为空时,进行测试

    输入:

    # 在项目根目录输入命令行
    $ python main.py dataset/empty.txt dataset/not_exist.txt dataset/ans.txt
    

    结果:

    提示错误结果,打印内容如下:

    性能分析

    性能统计表

    这是改进算法前的性能表

    这是改进算法后的性能表

    可以看到,改进算法后,性能有了明显的提高,免除了不必要的计算量以及使用矩阵运算后,性能提高了至少一百倍

    个人项目总结

    学习到的东西

    通过本次个人项目,我学习到了一些平时课堂上学不到的东西:

    • 文档的编写,作为一个程序员,我们要做好的事情不仅仅是编写代码,还包括写好一份开发文档。在这次项目中,我通过查找网上的资料以及参考 GitHub 上一些比较规范的项目的文档,学习了各种开发文档的规范编写,诸如模块说明文档、接口文档、设计文档、需求文档等,并尝试亲手完成一份规范的开发文档
    • Python 代码的规范书写,在 PSP 过程中,有要求对开发代码进行规范,为此,我查找了各种 Python 代码的规范文档。最后参考了 PEP8 编码规范和 Google 的Python 代码规范,并结合自己项目的实际情况,制定了一系列代码规范,并将代码规范写成规范文档
    • Git 管理工具的使用,虽然这个工具在之前参与项目的时候有使用过,但这次个人项目中,我通过查找网上的资料,也制定了一系列签入规范(如提交时应该注明本次提交的性质)
    • 学习了 SimHash 算法以及如何对算法进行改进
    • 代码的测试,通过这次个人项目,我通过对自己项目的各种测试,我也学会了如何使用 Python 和 Pycharm 对代码进行测试,并将部分结果编写成测试文档

    可以改进的地方

    本次项目也有一些值得思考和改进的地方:

    • 在设计方面,一些细节问题还未考虑清楚(如,文件管理模块与计算模块的数据流通形式),在编码过程中才逐步完善,主要原因还是编程经验上的不足,改进的方法如下:
      • 通过以后的一些编程练习,增强代码的熟练程度
      • 通过建立问题跟踪文档,将暂时解决不了的问题记录下来,通过后期与他人讨论或者查阅资料解决问题
    • 在测试方面,做得还不够规范,对一些性能方面的细节还没有过多测试,改进方法:
      • 可以通过查阅一些资料以及书籍来学习一些测试方法
      • 可以学习一些 Python 语言的测试工具,来做到更好的测试
  • 相关阅读:
    github分支规范
    前端工程师为什么要学习编译原理?
    现代编译原理——第六章:中间树 IR Tree 含源码
    现代编译原理——第五章:活动记录
    现代编译原理——第四章:语义分析以及源码
    现代编译原理——第三章:抽象语法树以及源码
    现代编译原理——第二章:语法分析之LL(K)
    现代编译原理——第1章:词法分析
    现代编译原理——第0章
    优雅的数组降维——Javascript中apply方法的妙用
  • 原文地址:https://www.cnblogs.com/Boyle-Coffee/p/13727666.html
Copyright © 2011-2022 走看看