結對第二次—文獻摘要熱詞統計及進階需求

做業格式

做業正文

1.PSP表格

PSP Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
Planning 計劃
• Estimate • 估計這個任務須要多少時間 15 15
Development 開發
• Analysis • 需求分析 (包括學習新技術) 30 120
• Design Spec • 生成設計文檔 30 15
• Design Review • 設計複審 30 15
• Coding Standard • 代碼規範 (爲目前的開發制定合適的規範) 30 30
• Design • 具體設計 60 80
• Coding • 具體編碼 240 210
• Code Review • 代碼複審 30 15
• Test • 測試(自我測試,修改代碼,提交修改) 60 90
Reporting 報告
• Test Repor • 測試報告 30 80
• Size Measurement • 計算工做量 30 30
• Postmortem & Process Improvement Plan • 過後總結, 並提出過程改進計劃 30 45
合計 585 745

2.解題思路描述

  • 思考過程
    • 看到這個題目時,一開始只是粗略地大概看了一下需求是什麼,因此一開始並無感覺到太大的難度。由於接觸Java語言比較多,因此也選擇用Java語言開發。可是在仔細研究過題目的需求後,發現細節問題不少。
    • 初步思路是用Java中的文件處理相關類來實現,而後使用ArrayList和Map等數據結構對字符數、單詞數等進行統計排序和輸出。
    • 在閱讀到進階需求時,由於以前有使用Python語言完成過一個原生爬蟲,因此對爬蟲有必定的瞭解。可是進階需求中的一些需求比較懵,因此也在微信羣裏交流了一下你們對需求的理解。
  • 資料查找
    • 對於接觸得比較偏少的知識點,主要仍是經過向同窗請教,或者上百度、也有到GitHub上搜索相應功能的demo,尋找相關的解決方法。

3.設計實現過程

  • 基本需求
    • 項目結構:
      • 221600308&221600340
        • -src
          • -Main.java
          • -WordCount.class
    • 關係與流程
      • 基本功能較爲簡單,有一個WordCount類,經過類內主函數調用writeFile方法和 getCount方法完成整個的功能。
    • 類圖
  • 進階需求
    • 項目結構
      • -src
        • -Main.java
        • -Main.class
        • -BaseFunction.class
        • -FileOperate.class
      • -scr
        • -result.txt(爬蟲結果)
        • -Main.java(爬蟲程序,能夠爬取CVPR2018論文列表)
        • -Main,class(編譯生成的可運行程序)
    • 爬蟲工具:Java Html解析器——Jsoup
    • 爬蟲思路
      • 經過Http請求獲得CVPR2018官網的html文檔,經分析獲得,論文的標題在div.class=「ptitle」中,經過getElementsByClass(「ptitle」)->ptitle.getElementsByTag(「a」).attr(「href」),並基礎地址「http//openaccess.thecvf.com/」拼接,獲得每一篇論文的訪問地址。
      • 進入論文頁面後,根據Html文檔經過選擇器doc.select(「div#papertitle」).first().text()和doc.select(「div#abstract」).first().text()獲取到論文的Title和Abstract按格式輸出到指定文件中。
    • 關係與流程
      • 分爲三個類Main、BaseFunctionFileOperate。經過Main函數獲取參數,調用BaseFunction中的方法計算。最後經過FileOperate中的方法進行文件讀寫操做。
    • 類圖
  • 關鍵函數流程圖
    python

  • 算法的關鍵以及關鍵實現部分流程圖
    git

4.性能分析

  • 性能分析圖

    github

  • 程序中消耗最大的函數
    • CountPhrase(String text,int cwords,int wei)

5.代碼說明

  • LineCount()
    • 遍歷內容,使用flag標記,若遇到有效內容設置爲true,若遇到\n且flag爲true則有效行數加1。
/**
     * 統計有效行數
     * @param text
     * @return
     */
    public int LineCount(String text){
        
        int lines=0;
        boolean flag = false;
        for(int i=0;i<text.length();i++){
            if(text.charAt(i)>' '){
                flag=true;
            }
            else if(text.charAt(i)=='\n'){
                if(flag) {
                    lines++;
                    flag=false;
                }
            }
        }
        if(flag)
            lines++;
        return lines;
    }
  • WordCount()
    • 將內容所有轉換爲小寫字母,將內容中的單詞分隔符所有替換爲空格,在對其替換後內容進行分割,並遍歷全部內容找尋有效單詞put到map中並計數。
/**
     * 詞頻統計
     * @param text
     * @return
     */
    public int WordCount(String text){
        int cpmount = 0;
        //所有字母轉小寫
        String textLow = text.toLowerCase(); 
        //正則表達式,過濾非字母數字字符
        String regex = "[^0-9a-zA-Z]"; 
        //過濾文本
        textLow = textLow.replaceAll(regex, " "); 
        //分割文本成單詞
        StringTokenizer words = new StringTokenizer(textLow);
        try {
            while (words.hasMoreTokens()) {
                String word = words.nextToken();
                //判斷單詞前4個是否爲字母
                if (word.length() >= 4 && Character.isLetter(word.charAt(0)) && Character.isLetter(word.charAt(1)) && Character.isLetter(word.charAt(2)) && Character.isLetter(word.charAt(3))) {  
                    cpmount++;
                    if (!wordCount.containsKey(word)) {
                        wordCount.put(word, new Integer(1));
                    } else {
                        int count = wordCount.get(word) + 1;
                        wordCount.put(word, count);
                    }
                }

            }
        }catch (Exception e){
            //錯誤
        }
        return cpmount;
    }
  • CountWord()
    • 將內容所有轉換爲小寫字母,將內容中的單詞分隔符所有替換爲空格,在對其替換後內容進行分割
    • 遍歷全部內容找尋有效單詞put到map中並計數,這裏會根據輸入的權重來計數。
/**
     * 統計單詞數
     * @param text
     * @param wei ,當wei=1 權重爲10  wei=0 權重爲1
     * @return 單詞數量
     */
    public int CountWord(String text,int wei){
        int ant=0;
        text = text.toLowerCase();
        //分隔符集合
        String regex = "[^0-9a-zA-Z]";
        text = text.replaceAll(regex, " ");
        //分割文本成單詞
        StringTokenizer words = new StringTokenizer(text); 
        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個是否爲字母
                    ant++;
                    if (!wordCount.containsKey(word)) {

                        wordCount.put(word, new Integer(wei==1 ? 10:1));
                    } else {
                        int count = wordCount.get(word) + (wei==1 ? 10:1);
                        wordCount.put(word, count);
                    }
                }
            }
        }catch (Exception e){
            //錯誤
        }
        return ant;
    }
  • CountPhrase()
    • 將內容所有轉換爲小寫字母並替換換行符爲空字符串,並使用分隔符將內容進行分割。
    • 遍歷全部內容尋找有效單詞,當尋找的單詞數量達到要求的詞組數量後,取出原文中間的分隔符對詞組進行拼接,而後put到map中統計數量,這裏會根據輸入的權重來計數。
/**
     * 統計詞組
     * @param text
     * @param cwords 詞組的單詞數
     * @param wei ,當wei=1 權重爲10  wei=0 權重爲1
     */
    public void CountPhrase(String text,int cwords,int wei){
        text = text.toLowerCase();
        text = text.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(text,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()>=cwords){//達到詞組單詞數量
                        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( wei==1 ? 10:1 ));
                        }
                        else{
                            int count=phraseCount.get(wword.toString()) + (wei==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){
            //出錯
        }

    }
  • sortList()
    • 獲取詞組map,轉換成一個list,自定義一個比較器對象,該對象能夠根據map的value值進行排序,最後將list使用該比較器進行排序
/**
     * 詞頻排序
     * @return list
     */
    public List<HashMap.Entry<String, Integer>> sortList(){

        List<HashMap.Entry<String, Integer>> list = new ArrayList<>();

        for(Map.Entry<String, Integer> entry : phraseCount.entrySet()){
            list.add(entry);
        }
        Comparator<Map.Entry<String, Integer>> comp = new Comparator<Map.Entry<String, Integer>>(){
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                if(o1.getValue().equals(o2.getValue()))
                    return o1.getKey().compareTo(o2.getKey());     //值相同 按鍵返回字典序
                return o2.getValue()-o1.getValue();
            }
            //逆序(從大到小)排列,正序爲「return o1.getValue()-o2.getValue"
        };
        list.sort(comp);
        return list;
    }

}

6.構建之法應用

  • 學習到的相關內容
    • 本次做業主要實踐了《構建之法》第2章中的單元測試、效能分析等內容以及第4章中的結對編程的部分。在書中學習到單元測試的基本知識,例如如何建立單元測試,好的單元測試標準等等。另外,也學習到與隊友溝通的幾種方式,知道該如何正確地給予反饋給隊友,在這些學習以後,我與隊友的溝通順利了很多,也愈來愈有默契。
  • 困難及解決方法
    • 最大的困難多是一開始的需求理解產生分歧,以往實踐課或者老師佈置的做業並無羅列詳細的需求,而是告訴咱們須要作一個什麼東西,有幾個需求。因此剛看到做業題目的時候,咱們兩我的不斷地扣字眼,時間花費也超出預期。不過在學習使用書中的一些溝通方式技巧以後,兩我的最後仍是達成了一致,而且在結對編程中,由於有較明確的分工,編碼時間比預期地更少了。
  • 評價你的隊友
    - 值得學習的地方
    - 最值得學習的地方多是有責任感,不容易放棄。由於最近又要找實習又要參加比賽還有校賽要辦,我原本的打算是好好地作完基本需求就能夠了,可是,個人隊友主動承擔下來了進階需求的大部分的代碼編寫,還提出想試試加個繪製圖表的功能。「要作就作到最好。」他的話對我起到了鼓勵做用,讓我也堅持盡力一塊兒把這個做業的進階需求以及附加設計作完。並且在進階需求部分有趕上一些小問題,他都一個個去解決了。要是我一我的作這個做業,我想我或許會放棄進階部分。
    - 須要改進的地方
    - 可能須要多一點的細心。代碼註釋能夠再多一點點。

7.附加題設計與展現

  • 創意描述
    • 前段時間在學習Python的Matplotlib庫時,學習到了一些可視化圖表的繪製方法,靈機一動,發現爲統計出來的詞頻繪製一個可視化的條形圖圖表不失爲一個簡單可是實用的小功能。(根據Java程序統計出來的Top10詞頻)
  • 實現方法
    • 根據java程序輸出的top10詞頻,做爲python程序的輸入。利用Matplotlib繪製出詞頻條形圖,使用戶更直觀地感覺詞頻之間的對比。
  • 主要代碼
x = np.array(['neural networks','this paper','object detection','convolutional neural','generative adversarial','show that','neural network','pose estimation','semantic segmentation','large-scale'])
y = np.array([479,470,453,366,340,340,305,298,280,240])

plt.bar(x,y,0.7,alpha=0.5,color='r')
plt.xticks(rotation=90,fontsize=12)
plt.show()
  • 實現成果展現
相關文章
相關標籤/搜索