第一次个人编程作业

这个作业属于哪个课程 19级网三网四软件工程
这个作业要求在哪里 作业要求
这个作业的目标 <实现论文查重算法,学会使用PSP表格估计,学会单元测试>

个人作业github地址

一、PSP表格

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

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

1.主要实现类

其中Main类是作为程序的入口
Calculate类是将转换为字符串后的两个文本从词频的角度进行相似度计算
FileUtil类是用来进行文本与字符串之间的转换

Calculate类中的主要方法

采用HanLP提供的方法将文本分词后返回

对两个词组进行合并,获取共有的词

获取该词组在总词组中的词频

计算两个句子的相似度


其中计算相似度用到了 TF-IDF与余弦相似性的应用(二):找出相似文章

假设有两个句子A,B
  句子A:我喜欢吃苹果,不喜欢吃榴莲。
  句子B:我不喜欢吃苹果,也不喜欢吃榴莲。
第一步,分词。
  句子A:我/喜欢/吃/苹果,不/喜欢/吃/榴莲。
  句子B:我/不/喜欢/吃/苹果,也/不/喜欢/吃/榴莲。
实现:通过IKAnalyzer中文分词器实现,即通过查询内置的词典进行分词
第二步,列出所有的词。
  我,喜欢,吃,苹果,榴莲,不,也。
第三步,计算词频。
  句子A:我 1,喜欢 2,吃 2,苹果 1,榴莲 1,不 1,也 0。
  句子B:我 1,喜欢 2,吃 2,苹果 1,榴莲 1,不 2,也 1。
第四步,写出词频向量。
  句子A:[1, 2, 2, 1, 1, 1, 0]
  句子B:[1, 2, 2, 1, 1, 2, 1]
实现:词与词频是键值对的形式,因此可以用哈希表来存储
到这里,问题就变成了如何计算这两个向量的相似程度。
我们可以把它们想象成空间中的两条线段,都是从原点([0, 0, ...])出发,指向不同的方向。两条线段之间形成一个夹角,如果夹角为0度,意味着方向相同、线段重合;如果夹角为90度,意味着形成直角,方向完全不相似;如果夹角为180度,意味着方向正好相反。因此,我们可以通过夹角的大小,来判断向量的相似程度。夹角越小,就代表越相似。
则计算A, B向量间的夹角的余弦值
假定a向量是[x1, y1],b向量是[x2, y2],那么可以将余弦定理改写成下面的形式:

余弦值越接近1,说明两向量间夹角越接近0,即两个句子越相似,因此余弦值即为两句子的相似度

2.程序流程图

将两个文本分别转换为字符串

将两个字符串输入Calculate提供的计算方法中,计算出结果并传给FileUtil,生成答案文件,
Calculate调用getSplitWords将文本分词,再合并出一个总词组,并计算出两个子词组的词频.计算出余弦相似度

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

public class CaculateTest {
    /**
     * 测试句子
     */
    @Test
    public void sentence(){
        String source = "我们去打球";
        String fake = "我们去学习";
        double res = Calculate.caculate(source,fake);
        assert res < 1;
    }
    /**
     *  测试与自身查重
     */
    @Test
    public void orig(){
        String source = FileUtil.fileToString("src/main/resources/testFile/orig.txt");
        String fake = FileUtil.fileToString("src/main/resources/testFile/orig.txt");
        double res = Calculate.caculate(source,fake);
        assert res == 1;
    }

    /**
     *  测试与增加版查重
     */
    @Test
    public void orig_add(){
        String source = FileUtil.fileToString("src/main/resources/testFile/orig.txt");
        String fake = FileUtil.fileToString("src/main/resources/testFile/orig_0.8_add.txt");
        double res = Calculate.caculate(source,fake);
        assert res <= 1;
    }

    /**
     *  测试与删减版查重
     */
    @Test
    public void orig_del(){
        String source = FileUtil.fileToString("src/main/resources/testFile/orig.txt");
        String fake = FileUtil.fileToString("src/main/resources/testFile/orig_0.8_del.txt");
        double res = Calculate.caculate(source,fake);
        assert res <= 1;
    }

    /**
     *  测试orig_0.8_dis_1.txt
     */
    @Test
    public void orig_dis(){
        String source = FileUtil.fileToString("src/main/resources/testFile/orig.txt");
        String fake = FileUtil.fileToString("src/main/resources/testFile/orig_0.8_dis_1.txt");
        double res = Calculate.caculate(source,fake);
        assert res <= 1;
    }

    /**
     *  测试orig_0.8_dis_10.txt
     */
    @Test
    public void orig_dis2(){
        String source = FileUtil.fileToString("src/main/resources/testFile/orig.txt");
        String fake = FileUtil.fileToString("src/main/resources/testFile/orig_0.8_dis_10.txt");
        double res = Calculate.caculate(source,fake);
        assert res <= 1;
    }

    /**
     *  测试orig_0.8_dis_15.txt
     */
    @Test
    public void orig_dis3(){
        String source = FileUtil.fileToString("src/main/resources/testFile/orig.txt");
        String fake = FileUtil.fileToString("src/main/resources/testFile/orig_0.8_dis_15.txt");
        double res = Calculate.caculate(source,fake);
        assert res <= 1;
    }

    /**
     * 测试自己编写的文本
     */
    @Test
    public void testOwnFile(){
        String source = FileUtil.fileToString("src/main/resources/testFile/testFileUtil.txt");
        String fake = FileUtil.fileToString("src/main/resources/testFile/testFileUtil.txt");
        double res = Calculate.caculate(source,fake);
        assert res == 1;
    }

    /**
     * 测试自己编写的文本
     */
    @Test
    public void testOwnFileWithCopy(){
        String source = FileUtil.fileToString("src/main/resources/testFile/testFileUtil.txt");
        String fake = FileUtil.fileToString("src/main/resources/testFile//testFileUtil_copy.txt");
        double res = Calculate.caculate(source,fake);
        assert res == 1;
    }

    /**
     * 测试自己编写的文本
     */
    @Test
    public void testOwnFileWithAdd(){
        String source = FileUtil.fileToString("src/main/resources/testFile/testFileUtil.txt");
        String fake = FileUtil.fileToString("src/main/resources/testFile//testFileUtil_add.txt");
        double res = Calculate.caculate(source,fake);
        assert res < 1;
    }

    /**
     * 测试自己编写的文本
     */
    @Test
    public void testOwnFileWithDel(){
        String source = FileUtil.fileToString("src/main/resources/testFile/testFileUtil.txt");
        String fake = FileUtil.fileToString("src/main/resources/testFile//testFileUtil_del.txt");
        double res = Calculate.caculate(source,fake);
        assert res < 1;
    }

}

测试覆盖率为

四、模块接口部分的性能改进


分析:程序在对文本的分词上花费了很长时间。

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

1.IOException

采用空文本与原文对比测试

FileNotFoundException

采用路径错误的文本与原文对比测试

六、测试结果 (部分)

原文本与orig_0.8_dis_1进行对比测试

原文本与orig_0.8_add进行对比测试

posted @ 2021-09-19 19:18  紀開  阅读(59)  评论(0)    收藏  举报