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

    第一次个人编程作业:论文查重

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

    • 类:

      1.readToString
      包含方法 String readToString(String fileName)
      读入文件名,把文件转为字符串。
      2.getCos
      包含方法 double getCos(String s1, String s2)
      计算两个字符串的余弦值。
      3.writeToAnswer
      包含方法 void writeIntoAnswer(double sum,String ans)
      将结果写入ans文件。
      
    • 流程图

    • 实现过程
       大致的过程在类中已经说明,这里主要写一下核心算法——余弦相似性的应用。
       先贴上参考资料: TF-IDF与余弦相似性的应用
       资料中是利用词频计算余弦相似性,这里不再赘述。讲讲踩的坑,我先尝试用字频方法写了一下,结果相当不理想:只有rep的结果接近0.8,其他大部分都在0.98左右,dis的几个文件结果甚至达到1。打开文件一看发现dis文本基本就是原文换个顺序或者加个回车(顺便一提一开始写的是对比每行的重复率,发现dis文本的重复率都奇低,因为中间插了回车= =直接拉胯)。到这里我想着用词频判断会不会好一点,于是又把字换成词(感谢安利我hanlphxd)。but,情况没有改善……我冷静下来仔细想想,这整个文本去掉标点,还不计顺序,词频和字频的区别也确实不大……
       总之待在坑里我想到另一个方法,原理还是算余弦,这次把所有词的出现位置用Map<String,Vector<Integer> >记录下来,于是每个词在两个文本中都对应有一个向量,也就是获得了这个词在两个文本中的位置向量,接下来可以计算它们的余弦值了。

    • 例:

      句子A:普通的DISCO我们普通的摇
      
      句子B:旁边普通的路人在普通的瞧
      

    如何计算以上两个句子的余弦值?

    • 第一步:分词
      在maven中配置hanlp,网上能搜到教程就不多说了,以及这里也踩到坑了,jdk版本太高居然还会配置失败……附个pom.xml文件的图吧

      搞半天终于成功了,泪目。

    • 第二步:列出所有词,存入它们出现的位置,注意只判断汉字

      句子A:普通0 的1 我们2 普通3 的4 摇5
      句子B:旁边0 普通1 的2 路人3 在4 普通5 的6 瞧7

    • 第三步:得到两个文本中所有词的位置向量

    举个栗子:

      普通:句子A:[0,3] 句子B:[1,5]
    
    • 第四步:计算两个文本中“普通”的余弦值:cosθ=(frac {0×1+3×5}{sqrt {0+3^2}×sqrt {1^2+5^2}})≈0.98

    余弦值可以表示两个向量之间的夹角大小,夹角越小,也就是余弦值越大,两个向量就越相似。(只是我这个不是二维的向量,其实我也不知道能不能叫向量……

    使用TreeMap存储词位置向量也是因为要确保是两个文本中相同的词对比,如果某个词只在一个文本中出现就不会被计算到。

    • 第五步:计算所有词的余弦值,同时记录词数。所有余弦值相加除以词数就是最终结果了。

    结果总算能看了。

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

    主要的改进思路都在实现过程↑里说了,也就是把词频向量改成词位置向量。如果没用词位置而是字位置应该会更慢,也更耗内存。少踩了一个坑导致现在不知道性能改进怎么写。

    性能分析

    • Overview
    • Live memory

    毕竟每个词都要开两个Vector……理所当然的吃内存。

    • CPU views

    没想到是matches消耗最大。主要是用来判断汉字了,也就是两个文本的每个字符都要判断一遍……这样想想也挺正常,但是这个好像无法避免啊……

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

    新增了重复率0和1的测试,其他几个用的是作业提供的样例。主要测试getCos方法。

    • 测试代码
    import org.junit.Assert;
    import static org.junit.Assert.*;
    public class mainTest {
    
        @org.junit.Test
        public void origAndOrig() {
            String s1=readToString.readToString("testfile/orig.txt");
            String s2=readToString.readToString("testfile/orig.txt");
            double sum=getCos.getCos(s1,s2);
            Assert.assertEquals(1.0,sum,0);
        }
        @org.junit.Test
        public void completeDiff(){
            String s1="乘风破浪会有时";
            String s2="直挂云帆济沧海";
            double sum=getCos.getCos(s1,s2);
            Assert.assertEquals(0,sum,0);
        }
        @org.junit.Test
        public void origAndAdd() {
            String s1=readToString.readToString("testfile/orig.txt");
            String s2=readToString.readToString("testfile/orig_0.8_add.txt");
            double sum=getCos.getCos(s1,s2);
            Assert.assertEquals(0.8,sum,0.2);
        }
        @org.junit.Test
        public void origAndDel() {
            String s1=readToString.readToString("testfile/orig.txt");
            String s2=readToString.readToString("testfile/orig_0.8_del.txt");
            double sum=getCos.getCos(s1,s2);
            Assert.assertEquals(0.8,sum,0.2);
        }
        @org.junit.Test
        public void origAndMix() {
            String s1=readToString.readToString("testfile/orig.txt");
            String s2=readToString.readToString("testfile/orig_0.8_mix.txt");
            double sum=getCos.getCos(s1,s2);
            Assert.assertEquals(0.8,sum,0.2);
        }
    

    后面的几个代码大同小异,就是改了个文件名,这里不放了。

    • 测试结果

    • 测试覆盖率


    核心方法getCos覆盖率为100%,readIntoString没覆盖到的都是catch块。

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

    参考资料

    • 空文本异常
          //测试
            try{
                throw new EmptyTextException("Empty Text!");
            }catch(EmptyTextException e){
                e.printStackTrace();
            }
    
    public class EmptyTextException extends Exception{
        public EmptyTextException(){
            super();
        }
        public EmptyTextException(String message){
            super(message);
        }
        public EmptyTextException(String message,Throwable cause){
            super(message,cause);
        }
        public EmptyTextException(Throwable cause){
            super(cause);
        }
    }
    
    
    • 测试结果

    5.PSP表格

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

    6.遇到的问题

    • 问题1
      创建测试的方法培训文档里讲的有点模糊,点击类名(我找了半天Solve在哪,原来是就是它的类名……),alt+enter就可以创建测试了。

    • 问题2

      照着预培训文档里面写,结果编译器报不能比较浮点数……?

    • 解决方法:应该用assertEquals(expected, actual, delta) 比较浮点数大小,只要期望值和声明值之间的差值小等于delta,那么就断言相等。Math.abs(expected - actual) <= delta

      这样写就没问题了

    • 问题3
      导jar包是最费劲的……好几次导出来结果命令窗口中执行出错。
      提示没有主清单解决方法:用WinRAR打开jar包,找到这个文件
      打开添加Main-Class: main,注意冒号后有空格。

      还有这个问题
      至今没明白具体原因,搜索到的答案基本都是说路径配置出错,然而我编译器里就运行的好好的……这种情况一般是导出的时候没设置好,就猜+搜+搞,莫名其妙就行了。

    7.总结

    我变秃了,也变强了

    • 第一次用jprofiler,第一次用git,第一次配置maven……学到了很多东西,主要是增强了查资料的能力……整个过程走下来写代码反而是最轻松的,学习新东西是最难的,单一个git的用法就研究了一下午。找到的教程总是走到一半就出问题,然后又去百度解决方法,怎么导jar包,怎么配置maven,怎么用git push,于是浏览器常常挂着好几个窗口。在过程中也意识到自己跟别人的差距,在别人眼里可能是常识的东西我得搞几小时,好在最后都顺利解决了。
    • 编码过程中同样遇到了一些困难,因为Java语言还不太熟练,写代码的时候下意识的想用C的东西,有时候写到一半开始面向百度编程。比如存词向量的存储,开始写了个map<string,vector>offset1,编译器直接报错,在编译器的提示下蒙出了正确写法Map<String, Vector> Offset1=new TreeMap<String,Vector>();
      ……害,积累的东西太少,现在开始吃亏了,好在这也是一个积累的过程,今后的学习和工作中总会派上用场吧。

    “你的负担将变成礼物,你受的苦将照亮你的路。”

  • 相关阅读:
    数组名与指向数组的指针
    如何实现带可变长参数的函数
    assert()的使用
    参数入栈的顺序以及栈/堆的生长顺序
    指向函数的指针
    各变量入栈顺序
    数组与指针
    C中空指针、NULL与0
    C中为什么不能用==比较字符串?
    在命令行窗口中输入EOF
  • 原文地址:https://www.cnblogs.com/blacksheep107/p/13646705.html
Copyright © 2011-2022 走看看