• 第一次个人编程作业


    本次作业已上传至GitHub

    PSP表格

    PSP2.1

    Personal Software Process Stages

    预估耗时(分钟)

    实际耗时(分钟)

    Planning

    计划

    60

    70

    · Estimate

    · 估计这个任务需要多少时间

    60

    70

    Development

    开发

    830

    1020

    · Analysis

    · 需求分析 (包括学习新技术)

    300

    350

    · Design Spec

    · 生成设计文档

    200

    210

    · Design Review

    · 设计复审

    50

    40

    · Coding Standard

    · 代码规范 (为目前的开发制定合适的规范)

    20

    30

    · Design

    · 具体设计

    30

    30

    · Coding

    · 具体编码

    100

    120

    · Code Review

    · 代码复审

    30

    20

    · Test

    · 测试(自我测试,修改代码,提交修改)

    100

    120

    Reporting

    报告

    370

    410

    · Test Repor

    · 测试报告

    300

    320

    · Size Measurement

    · 计算工作量

    20

    20

    · Postmortem & Process Improvement Plan

    · 事后总结, 并提出过程改进计划

    50

    70

    · 合计

    1260

    1500

    计算模块接口的设计与实现过程

    • 算法流程图
    • 算法思想

    整段代码用一个类(CosineSimilarity)封装,每个步骤分别用一个方法封装,最后用calculate方法串起来。
    接下来简单介绍一下CosineSimilarity类中的各个方法:

    1. init 构造方法。 用于传入两个文本
    2. extract_keyword 提取关键词。 先通过jieba分词,再把分词结果提取出前K个权重最大的关键词
    3. one_hot 对关键词进行one_hot编码。 把文本转为向量
    4. calculate 计算余弦相似度。 把前面的所有方法串起来,并计算得到结果

      这段代码参考了网上大佬的GitHub。如果只对分词结果进行余弦相似度的计算,对于短文本的准确率还可以,而对于长文本就不太行。因此,提取了前topK个关键词,对关键词进行相似度的计算,准确率会提高一点点。
      关于topK的选取: 取群里的测试数据,一篇文章大概由10000个词组成,按照topK从1-2000,依次验证一下,发现topK在1600以后基本收敛,而在1100左右性能较好。因此,选取topK = int(len(seg)/9),其中seg为文章的分词结果。这个选取方法不是很严谨,缺少更多数据的验证。

    验证的代码如下:

        import matplotlib.pyplot as plt
        y = []
        with open(r"test_dataorig.txt",encoding="utf-8") as fp:
            ori = fp.read()
        with open(r"test_dataorig_0.8_add.txt",encoding="utf-8") as fp:
            copy = fp.read()
        s = CosineSimilarity(ori,copy)
        x = [i for i in range(5,2000,5)]
        for i in range(5,2000,5):
            topK = i
            ans = s.calculate()
            y.append(ans)
            # print("topK = ",topK,"相似度:",ans)
        print(y)
        plt.plot(x,y)
        plt.xlabel("topK")
        plt.ylabel("rate")
        x2 = [5,2000]
        y2 = [0.8,0.8]
        plt.plot(x2,y2)
        plt.show()
    

    计算模块接口部分的性能改进

    • 运行时间分析

       利用Python的profile工具进行分析,分析完两篇文章的总时间是3.53s,其中耗时最大的是在jieba分词这一块,因为是调用第三方库,所以但从算法的角度不太懂得怎么优化,可能开个多线程速度会快一点。哦,还有,我的余弦相似度算法为图省事直接调用的sklearn的cosine_similarity,这个函数会计算输入的n个向量两两之间的相似度,因为这道题是两篇文章对比,所以时间上的差距可能不是很大,但是自己写个函数可能会快一点。

    • 消耗内存分析

      这里用了Python的memory_profiler和psutil库进行内存分析,因为是对文章进行分词并转为向量所以内存的消耗还是比较大的。其中内存消耗最大的模块是:

        @staticmethod
        def extract_keyword(content):  # 提取关键词
            # 切割
            seg = [i for i in jieba.cut(content, cut_all=True) if i != '']
            # 提取关键词
            keywords = jieba.analyse.extract_tags("|".join(seg), topK=topK, withWeight=False)
            return keywords
    

    计算模块单元测试展示

    • 测试代码

        root = "sim_0.8"
        fileName = os.listdir(root)  # 得到当前目录下所有的文件名
        with open(root+'\'+fileName[0],encoding='UTF-8') as fp:
            ori = fp.read()
            # print("len article = ",len(ori))
            seg = [i for i in jieba.cut(ori, cut_all=True) if i != '']
            topK = int(len(seg)/9)
        processText(ori)
        for i in range(1,10):
            with open(root+'\'+fileName[i],encoding='UTF-8') as fp:
                copy = fp.read()
                processText(copy)
                similarity = CosineSimilarity(ori,copy)
                similarity = similarity.calculate()
                print(fileName[i] + ' 相似度: %.2f%%' % (similarity*100)) 
    
    • 测试代码构建思路

      测试代码在本地完成,读取文件夹下的所有文件名,接着读入原文和修改过的文章,创建一个CosineSimilarity对象,调用对象的calculate方法,最后对结果保留两位小数并写入输出文件。

      测试数据采用群里提供的9个文件,这9个文件包括了大部分查重情况。

    • 测试结果

    orig_0.8_add.txt 相似度: 81.00%
    orig_0.8_del.txt 相似度: 70.50%
    orig_0.8_dis_1.txt 相似度: 89.00%
    orig_0.8_dis_10.txt 相似度: 75.00%
    orig_0.8_dis_15.txt 相似度: 58.50%
    orig_0.8_dis_3.txt 相似度: 86.50%
    orig_0.8_dis_7.txt 相似度: 82.50%
    orig_0.8_mix.txt 相似度: 80.50%
    orig_0.8_rep.txt 相似度: 70.50%

      从测试结果可以看出这个算法的准确度还算可以,但是感觉会偏低一点

    • 测试二

      利用两段相同的文本进行分析

    原文
      矛盾分析法是唯物辩证法的核心,唯物辩证法包括很多规律和范畴,其中,对立统一规律是其核心,在《矛盾论》的开头,事物的矛盾法则,即对立统一的法则,是唯物辩证法的最根本的法则。因而,掌握了矛盾分析法,我们就能更好地理解唯物辩证法的其他内容。
    修改后
      矛盾分析法是唯物辩证法的核心,唯物辩证法包括很多规律和范畴,其中,对立统一规律是其核心,在《矛盾论》的开头,事物的矛盾法则,即对立统一的法则,是唯物辩证法的最根本的法则。因而,掌握了矛盾分析法,我们就能更好地理解唯物辩证法的其他内容。

    测试结果

    相似度 100.00%

    • 单元测试代码

        
    class Test(unittest.TestCase):
        def test1(self):
            "改动0.8的文本"
            with open("sim_0.8orig.txt",encoding="utf-8") as fp:
                ori = fp.read()
            with open("sim_0.8orig_0.8_add.txt",encoding="utf-8") as fp:
                copy = fp.read()
            model = CosineSimilarity(ori,copy)
            ans = model.calculate()
            self.assertEqual(round(ans,2), 0.8)
        def test2(self):
            "相同文本"
            with open("sim_0.8orig.txt",encoding="utf-8") as fp:
                ori = fp.read()
            with open("sim_0.8orig.txt",encoding="utf-8") as fp:
                copy = fp.read()
            model = CosineSimilarity(ori,copy)
            ans = model.calculate()
            self.assertEqual(round(ans,2), 1.0)
        def test3(self):
            "空文本"
            with open("sim_0.8orig.txt",encoding="utf-8") as fp:
                ori = fp.read()
            with open("sim_0.8empty.txt",encoding="utf-8") as fp:
                copy = fp.read()
            model = CosineSimilarity(ori,copy)
            ans = model.calculate()
            self.assertEqual(ans, 0.0)
    
    if __name__ == '__main__':
        unittest.main()
    
    • 单元测试覆盖率

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

    • IO流异常
        try:
            with open(path,encoding='UTF-8') as fp:
                ori = fp.read()
        except:
            print("路径错误")
    

      当路径名有错时,可能无法打开文件,产生异常

    • 除0异常
        try:
            sim = cosine_similarity(sample)
            return sim[1][0]
        except Exception as e:
            print(e)
            return 0.0
    

    在计算两个向量的余弦值时,当输入的文本为空时,分母有可能为0,会产生异常

    小结

      这次作业最主要的收获是学会了用Git进行上传和下载项目和如何搭建一个项目的完整性,比如前期工作,性能分析,测试数据等,特别是单元测试,这在以前是根本不会去做的。在这之中体会到了代码不是最主要的,大部分的时间都在处理其他的事,比如写博客,学习新技术等,真正编码的时间只占了一小部分。同时,这次作业还提高了查找和收集资料的能力。

  • 相关阅读:
    《人件》读书笔记3
    《人件》读书笔记2
    《人件》读书笔记1
    《编程珠玑》读书笔记3
    《编程珠玑》读书笔记2
    学习进度报告2021/4/10
    《编程珠玑》读书笔记1
    学习进度报告2021/4/9
    学习进度报告2021/4/8
    关于软件体系架构质量属性的科技小论文
  • 原文地址:https://www.cnblogs.com/koun/p/13656341.html
Copyright © 2020-2023  润新知