zoukankan      html  css  js  c++  java
  • 第一次个人编程作业

    软件工程 点我
    作业要求 点我
    作业目标 熟练使用Git,并且与GitHub搭配;PSP模型;熟悉测试工具


    Github

    链接:

    https://github.com/MrEdge123/MrEdge123/tree/master/3118005414

    目录结构:

    module  		#模块
    |-- gen_vec.py			        #生成词频向量
    |-- simhash.py			        #simhash算法
    
    unit_test		#单元测试
    |-- gen_vec
        |-- test.py			        #测试代码
        |-- htmlcov
    	|-- test_py.html	        #代码覆盖率
    |-- simhash
        |-- test.py
        |-- htmlcov
            |-- test_py.html
    
    performance		#性能测试
    |-- time1.txt			        #修改前的时间
    |-- time2.txt			        #修改后的时间
    |-- memory.txt				#内存使用
    
    main.py             		        #主程序
    orig.txt     				#原论文
    orig_0.8*.txt				#对比论文
    requirements.txt			#依赖文件
    

    PSP

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

    接口设计与实现

    因为涉及中文的分词,所以使用了比较方便的结巴分词库。

    设计思路

    在这里插入图片描述

    接口

    gen_vec.py

    包含2个函数:gen_vec()check()

    1.函数原型:

    • check(str: word) -> bool : 检测word是否合法
    • gen_vec(list: words, dict: vec) -> none : 根据words, 生成词权值向量vec

    2.函数check()
    作用:检测word是否合法
    原理:通过word中每一个字符的Unicode编码,把中文和数字保留下来

    3.函数gen_vec()
    作用:生成词权值向量vec
    原理:通过字典的hash,建立词语和权值的映射。由于TF-IDF中的IDF比较难求,因此把词语的长度作为近似的权值。

    simhash.py

    包含3个函数:hash64()simhash()cmp_simhash()

    1.函数原型:

    • hash64(str: word) -> num:得到64位word的hash值
    • simhash(dict: vec) -> num:通过向量vec生成simhash签名
    • cmp_simhash(num: simhash1, num: simhash2) -> num:对比两个simhash的海明距离

    2.函数hash64()
    作用:通过字符串word生成64位的hash值
    原理:考虑到直接通过hash()函数,可能只会生成32位的hash值,因此对hash()的值进行平方,然后取模得到64位hash值。

    3.函数simhash()
    作用:把词权值向量转化为simhash签名
    原理:simhash算法

    4.函数cmp_simhash()
    作用:对比两个simhash的海明距离,然后得到相似度
    原理:相似度 = (64 - 海明距离) / 64,海明距离:把simhash值转化为64位二进制后,位置相同但值不同的位的个数。


    接口性能改进:simhash

    性能分析图(时间)

    在这里插入图片描述
    由上可知,最耗时的是结巴分词的时候,原因:分词时需要构建一个字典树,对于较长文本需要花费较多时间。所以我们可以看到,对抄袭文章进行分词时,速度大大减少。

    第二耗时的模块,是生成simhash签名的时候。时间复杂度为:(O(64 * cnt)),其中(cnt)为vec中词语的个数。现在想办法改进这个模块使用的时间。

    改进前代码

    # 计算64位hash
    def hash64(str) :
        return (hash(str) ** 2) % (2 ** 64) 
    
    # 计算vec的simhash
    def simhash(vec) :
        cnt = [0] * 64
        for key in vec :
            val = hash64(key)
            pos = 0
            while val > 0 :
                if val % 2 == 1 : cnt[pos] += vec[key]
                else : cnt[pos] -= vec[key]
                val = val / 2
                pos += 1
        
        pos = 0
        ans = 0
        while pos < 64 :
            ans = ans * 2
            if cnt[pos] > 0 : ans += 1
            pos += 1
    
        return ans
    

    通过位运算符优化后:

    改进后代码

    # 计算64位hash
    def hash64(str) :
        return (hash(str) ** 2) % (1 << 64) 
    
    # 计算vec的simhash
    def simhash(vec) :
        cnt = [0] * 64
        for key in vec :
            val = hash64(key)
            pos = 0
            while val > 0 :
                if val & 1 : cnt[pos] += vec[key]
                else : cnt[pos] -= vec[key]
                val = val >> 1
                pos += 1
        
        pos = 0
        ans = 0
        while pos < 64 :
            ans = ans << 1
            if cnt[pos] > 0 : ans += 1
            pos += 1
    
        return ans
    

    对比图

    改进前:
    在这里插入图片描述
    改进后:
    在这里插入图片描述


    模块单元测试:gen_vec

    模块及测试代码

    # 检查word是否合法
    def check(word) :
        if len(word) == 0 : return False
    
        ok = True
        for ch in word :
            if ch >= 'u4e00' and ch <= 'u9fa5' : ok = True # 中文字符范围
            # elif ch >= 'a' and ch <= 'z' : ok = True
            # elif ch >= 'A' and ch <= 'Z' : ok = True
            elif ch >= '0' and ch <= '9' : ok = True
            else : return False
    
        return True
    
    # 根据words, 生成词频向量vec
    def gen_vec(words) :
        vec = {}
        for key in words :
            if check(key) : vec[key] = len(key)
        return vec
    
    if __name__ == "__main__" :
        words = ["我", "", "
    ", "去", "跑步", "2", "w", "word", "HaHa"]
        vec = gen_vec(words)
    
        for key in vec :
            print(key + ":" + str(vec[key]))
    
    

    测试数据及构造思路

    测试数据:words = ["我", "", " ", "去", "跑步", "2", "w", "word", "HaHa"]

    思路:由上代码可知,我们主要应该测试check()函数。check()函数返回True的条件:word的长度不为0,且其中的字符由中文(因为是中文论文查重)或者数字构成。所有有:
    返回为True的数据:["我", "去", "跑步", "2"]
    返回为False的数据:["", " ", "w", "word", "HaHa"]

    代码覆盖率

    在这里插入图片描述


    异常处理:main.py

    1.传入参数的数量不够
    在这里插入图片描述
    样例:
    在这里插入图片描述

    2.文件路径出错
    样例
    在这里插入图片描述


    结果

    orig_0.8_add.txt
    在这里插入图片描述

    orig_0.8_del.txt
    在这里插入图片描述

    orig_0.8_dis_1.txt
    在这里插入图片描述

    orig_0.8_dis_10.txt
    在这里插入图片描述

    orig_0.8_dis_15.txt
    在这里插入图片描述


    总结

    这个项目的难点不在于算法,而在于对各种测试工具的使用。这次项目我学到了:

    • 用Git、Github和vscode对代码进行管理
    • python的使用(之前一直用C++写代码)
    • 性能分析工具:line_profile和memory_profiler的使用
    • 代码覆盖率:coverage的使用
  • 相关阅读:
    MFC Windows 程序设计>WinMain 简单Windows程序 命令行编译
    AT3949 [AGC022D] Shopping 题解
    CF643D Bearish Fanpages 题解
    CF643C Levels and Regions 题解
    CF241E Flights 题解
    CF671C Ultimate Weirdness of an Array 题解
    CF1592F Alice and Recoloring 题解
    GYM 102452E 题解
    CF494C Helping People 题解
    P5556 圣剑护符
  • 原文地址:https://www.cnblogs.com/happy-MEdge/p/13726183.html
Copyright © 2011-2022 走看看