福大软工1816 · 第五次作业 - 结对作业2

作业说明

本人博客链接

队友博客链接

github地址

分工情况

具体分工说明 分工
1. 编写爬虫爬取论文信息 叶一帆
2. 自定义输入输出文件 叶一帆
3. 加入权重的词频统计 林世杰
4. 新增词组词频统计功能 林世杰
5. 自定义词频统计输出 叶一帆
6. 多参数的混合使用 叶一帆
7. 附加题 叶一帆
8.性能分析与改进 叶一帆
9.单元测试 林世杰,叶一帆

PSP

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

解题思路

  • 爬虫部分(自己写的):

        这里用到了Java的两个包,httpclientjsoup ,本来是直接用jsoup解析,但是发现解析后的内容不全,有部分html源码没生成全就解析了,所以加了httpclient,先请求读取网页,然后用jsoup开始解析。

        整个爬虫流程:先找到标签的class为ptitle的段,然后获取链接,但是这里的链接是相对地址,所以完整的链接需要自己拼接。这样就能拿到一个论文列表的url表。然后遍历每个链接,解析找标签的值为papertitleabstract的文本,分别对应标题跟摘要。然后各种拼接字符串。

        大体流程:

  • 代码组织与内部实现设计

    • 自定义输入输出文件:同上次作业,获取CLI上的参数,然后new一个File并且判断读写异常。

    • 加入权重的词频统计:判断标题还是摘要,然后个数加1|10

    • 新增词组词频统计功能:

      用一个队列存给定词组长度的单词。

      1. 判断单词是否为合法单词:合法单词入队;队列全部清空。
      2. 如果队列长度达到给定长度,则存储到Map中。
      3. 队首出队一个,队尾继续入队。
      4. 循环①操作。
    • 自定义词频统计输出:把固定值全部写成变量的形式。

    • 多参数的混合使用:获取CLI的各种参数判断,调用对应的模块或者做出对应的异常抛出

附加题设计与展示

  • 设计的创意独到之处:把全部已知的数据做一个分析+可视化处理。做到所见即所得,一眼就能看出这次论文的作者有多少,这次论文哪个类型的最多,这次活动最火的名词热词是什么,这次哪个地区的论文数量最多,又或者哪几个作者之间有关系。。
  • 实现思路:先用java做各种数据处理分析,然后输出analy_result.txt,这个文本里包含一千多篇论文的类别、标题、摘要、作者以及作者来自、PDF链接。然后继续导出各种json文件,包含各种数据,由于时间问题,没用java做图形化。用pyecharts库快速生成图形化表格,对应文件cvpr数据可视化.html
  • 实现成果展示:文件在github,这里展示几个图。
    由于全部作者的图太大这里就展示部分:

    作者关系图

热词高频词组

不同类型的论文统计图

不同地区的论文发表数

关键代码展示

  • 具有价值的代码片段
/*
     * 统计词组
     * 参数 字符串 ant:词组的单词数  ty权重类型
     *  ty 参数当ty==1 权重为10  ty==0 权重为1
     */
    public void CountforPhrase(String ss,int ant,int ty){
        ss = ss.toLowerCase();
        ss = ss.replaceAll("\n","");
        StringBuilder mid=new StringBuilder();//分隔符
        StringBuilder wword=new StringBuilder();//单词拼接
        Queue<String> que1=new LinkedList<String>();//用于存储词组单词
        Queue<String> que2=new LinkedList<String>();//用于存储分隔符
        String feng=",./;'[] \\<>?:\"{}|`~!@#$%^&*()_+-=";//分隔符集合
        StringTokenizer words = new StringTokenizer(ss,feng,true); //分割文本成单词。
        try {
            while (words.hasMoreTokens()) {
                String word =words.nextToken();
                if (word.length() >= 4 && Character.isLetter(word.charAt(0)) && Character.isLetter(word.charAt(1)) && Character.isLetter(word.charAt(2)) && Character.isLetter(word.charAt(3))) {  //判断单词前4个是否为字母

                    que2.offer(mid.toString());
                    mid.delete(0,mid.length());
                    que1.offer(word);
                    if(que1.size()>=ant){//达到词组单词数量
                        int cnt=0;
                        wword.delete(0,wword.length());
                        for(String w:que1){
                            wword.append(w);
                            cnt++;
                            if(que2.size()>cnt)
                            {
                                String tmp=((LinkedList<String>) que2).get(cnt);//取出中间的分隔符
                                wword.append(tmp);//拼接
                            }
                        }
                        //最后生成正确的wword 词组
                        // 进行统计操作
                        if(!phraseCount.containsKey(wword.toString()))
                        {
                            phraseCount.put(wword.toString(),new Integer( ty==1 ? 10:1 ));
                        }
                        else{
                            int count=phraseCount.get(wword.toString()) + (ty==1 ? 10:1);
                            phraseCount.put(wword.toString(),count);
                        }
                        que1.remove();
                        que2.remove();
                    }
                }
                else if(word.length()!=1){//不符合条件 将其前面的都删除
                    que1.clear();
                    que2.clear();
                }else if(word.length()==1 && !(Character.isLetter(word.charAt(0)))){//判断是否为分隔符
                    mid.append(word);
                }
            }
        }catch (Exception e){
            System.out.println("词频统计报错:");
            System.out.println(e.getMessage());
        }

    }

性能分析与改进

  • 改进思路:目前没有改进,在写的过程中一边调优一边实现功能。

  • 展示性能分析图和程序中消耗最大的函数:

代码覆盖率的图:

覆盖率最高的函数——词组词频统计

性能分析图:

单元测试

  • 展示出项目部分单元测试代码
    脏数据

    1.txt&2.txt


    3.txt


    读空文件

  • 说明测试的函数
    fileRead是文件读写类,负责读写。
    output是临时提取出来的,跟写的格式一致。

  • 构造测试数据的思路

Github的代码签入记录

  • 合理的commit信息

遇到的代码模块异常或结对困难及解决方法

  • 问题描述:

    字符串处理、乱七八糟的,非ascii会显示不全之类的干扰统计。

  • 做过哪些尝试:

    直接把字符串清洗一遍再开始处理词频统计。

  • 是否解决:

    不知道是否解决,反正测试过来没问题。

  • 有何收获:

    学会了字符串的各种处理。

评价你的队友

  • 值得学习的地方

    人好相处,由于打acm的,在算法结构上思维比较缜密。

  • 需要改进的地方

    由于经常敲C++跟刷OJ题,一些实战的地方,或者其他语言比如Java或者python,不是那么熟悉,可以多接触接触。

学习进度条

第N周 新增代码(行) 累计代码(行) 本周学习耗时(小时) 累计学习耗时(小时) 重要成长
5 1000+ 1000+ 30 30 Lua流程控制学习、
6 1000+ 1000+ 5 5 复习java
posted @ 2018-10-10 20:11  _NeverSayDie  阅读(240)  评论(1编辑  收藏  举报