18軟工實踐-第五次做業-結對做業2

結對同窗的博客連接
本做業博客的連接
Github項目地址
附加功能代碼
代碼規範連接html

  • 具體分工

    莊卉:爬蟲、詞頻權重計算+自定義統計輸出、附加功能、博客撰寫
    胡緒佩:詞組詞頻統計功能+字符及有效行數目、單元測試、性能分析、博客撰寫java

  • PSP表格

    PSP2.1 Personal Software Process Stages 預估耗時(分鐘) 實際耗時(分鐘)
    Planning 計劃 30 30
    · Estimate · 估計這個任務須要多少時間 30 30
    Development 開發 1770 1740
    · Analysis · 需求分析 (包括學習新技術) 120 150
    · Design Spec · 生成設計文檔 30 30
    · Design Review · 設計複審 30 30
    · Coding Standard · 代碼規範 (爲目前的開發制定合適的規範) 30 60
    · Design · 具體設計 120 90
    · Coding · 具體編碼 900 720
    · Code Review · 代碼複審 180 180
    · Test · 測試(自我測試,修改代碼,提交修改) 360 480
    Reporting 報告 120 120
    · Test Repor · 測試報告 60 30
    · Size Measurement · 計算工做量 30 20
    · Postmortem & Process Improvement Plan · 過後總結, 並提出過程改進計劃 30 70
    合計 1920 1890
  • 解題思路描述與設計實現說明

    • 爬蟲使用

      爬蟲語言使用的是python(爲何沒使用java至今仍是個迷,對沒加成分有點心痛
      用urllib.request抓取頂會論文列表網址獲得源代碼,beautifulsoup配合正則(附加功能爬蟲使用到)便可獲得論文列表的基本信息。
    f = open("result.txt", 'a', encoding='utf-8')
      html1 = urllib.request.urlopen("http://openaccess.thecvf.com/CVPR2018.py").read()
      bf1 = BeautifulSoup(html1)
      texts1 = bf1.select('.ptitle')
      a_bf = BeautifulSoup(str(texts1))
      a = a_bf.find_all('a')
      urls = []
      for each in a:
          urls.append("http://openaccess.thecvf.com/" + each.get('href'))
      for i in range(len(urls)):
          f.write(str(i))  
          f.write("\n")
          html2 = urllib.request.urlopen(urls[i]).read()
          bf = BeautifulSoup(html2)
          texts2 = bf.find_all('div', id='papertitle')
          f.write("Title: " + texts2[0].text.lstrip('\n') + "\n")  
          texts3 = bf.find_all('div', id='abstract')
          f.write("Abstract: " + texts3[0].text.lstrip('\n') + "\n\n\n")
    • 代碼組織與內部實現設計

      代碼文件組織
031602114&031602444
|- src
  |- WordCount.sln
  |- WordCount
      |- CharCount.cpp
      |- CharCount.h
      |- LineCount.cpp
      |- LineCount.h
      |- WeightTypeNE.cpp
      |- WeightTypeNE.h
      |- SortTopN.cpp
      |- SortTopN.h
      |- Word_Group_Cnt.cpp
      |- Word_Group_Cnt.h
      |- WordCount.cpp
      |- WordCount.h
      |- pch.cpp
      |- pch.h
      |- main.cpp
      |- WordCount.vcxproj
|- cvpr
   |- Crawler.py
   |- result.txt
關係圖

  • 說明算法的關鍵與關鍵實現部分流程圖

    單詞權重計算python

    根據我的項目判斷有效單詞的算法進行改進,講按字符串讀取改爲按行讀取,判斷該行是title仍是absract,經過存儲分割符的位置進行切割讀取有效詞並計算權重。
    詞組切割
    根據用戶輸入決定詞組切割長度,切割過程當中借用隊列輔助存儲每個合法單詞的長度,遇到不合法單詞則能夠將隊列que清空便可,不然就根據詞組單詞組成長度以及隊列存儲的單詞長度進行進隊出隊操做,達到更新string後進行截取(使用substr庫函數)獲得新的詞組存入map容器。c++

  • 附加題設計與展現

    1. 爬蟲能力有限orz,只從網站綜合爬取論文的除題目、摘要外其餘信息。爬蟲語言使用python。額外爬取信息有:做者、PDF連接、SUPPPDF連接、ARXIV連接。
      txt文件如圖:
      git

    2. 想象力有限orz,咱們分析了論文列表中各位做者之間的關係,論文A的第一做者可能同時是論文B的第二做者,不一樣論文多位做者之間可能存在着聯繫,並將關係可視化。
      咱們從附加功能1的txt文件提取了發表在2018cvpr頂會上的全部論文的第一做者和第二做者,使用分析工具NodeXL作出了關係圖譜。
      圖譜全貌以下:

      逐漸剔除較少聯繫點的圖譜以下:
      github


    (沒有第二做者時在第二做者處填empty)算法

    能夠看出在2018cvpr上發表論文且是主要做者的大神就是——Qi Wu,緊接着還有Wei Wang,Tomer Michaeli,Ross Girshick等等。(而後發表數目多的主要做者們互相之間都不合做的嗎……
    1. 修改了了基本功能的代碼,輸出了發表最多論文的做者top10並將其可視化。

    能夠看出發表論文最多的做者是Ming-Hsuan Yang,在2018cvpr上一共發表了17篇論文。flask

  • 關鍵代碼解釋

具體解釋: 使用輔助隊列存儲每一個合法單詞的長度,經過入隊和出隊操做更新string進行截取不斷得到新的詞組;函數詳情在如下.h文件中均有描述;app

  • 詞組統計.h文件
  • 詞頻排序.h文件
  • 單詞統計.h文件
/*統計指定長度的合法單詞量造成的詞組詞頻*/
void Word_Group_Cnt(int word_Group_Len, string str, map <string, int > &group_Map,int ttl_Abs)
{
    string word_Now = "";
    string word_Group = "";
    int lenth = str.length();
    queue <int> que;
    for (int i = 0; i < lenth; i++)
    {
        if (Is_Num(str[i]) || Is_Engch(str[i]) && i != lenth - 1)                   //字符是字母或數字就將其鏈接到word_Now
        {
            word_Now += str[i];
            continue;
        }
        else if (Is_Num(str[i]) || Is_Engch(str[i]) && i == lenth - 1)              //字符是字母或數字且爲字段末位鏈接後就須要對末尾的單詞判斷是否爲合法單詞,不然會跳出循環漏掉末尾一個單詞;
        {
            word_Now += str[i];
            word_Now = Is_Word(word_Now);
            int word_Len = word_Now.length();
            if (word_Len >= 4)
            {
                word_Group += word_Now;
                if (que.size() == word_Group_Len - 1)
                {
                    group_Map[word_Group] += ttl_Abs;
                }
                else if (que.size() > word_Group_Len - 1)
                {
                    word_Group = word_Group.substr(que.front());
                    group_Map[word_Group] += ttl_Abs;
                }
            }
            else if (word_Len >= 0 && word_Len < 4)
            {
                continue;
            }

        }
        else
        {
            word_Now = Is_Word(word_Now);
            int word_Len = word_Now.length();
            if (word_Len >= 4)
            {
                word_Group += word_Now;
                if (que.size() < word_Group_Len - 1)                    //隊列大小比所需合法單詞數word_Group_Len-1小狀況
                {
                    word_Group += str[i];
                    word_Len += 1;
                    while (!Is_Num(str[i + 1]) && !Is_Engch(str[i + 1]) && i + 1 < lenth)
                    {
                        word_Group += str[i + 1];
                        word_Len += 1;
                        i += 1;
                    }
                    que.push(word_Len);
                    word_Now = "";
                }
                else if (que.size() == word_Group_Len - 1)              //隊列大小=所需合法單詞數word_Group_Len-1狀況
                {
                    group_Map[word_Group] += ttl_Abs;
                    word_Group += str[i];
                    word_Len += 1;
                    while (!Is_Num(str[i + 1]) && !Is_Engch(str[i + 1]) && i + 1 < lenth)
                    {
                        word_Group += str[i + 1];
                        word_Len += 1;
                        i += 1;
                    }
                    que.push(word_Len);
                    word_Now = "";
                }
                else if (que.size() > word_Group_Len - 1)               //隊列大小等於詞組所需合法單詞數量,則對隊列進行進隊和出隊操做更新string並進行截取
                {
                    word_Group = word_Group.substr(que.front());
                    group_Map[word_Group] += ttl_Abs;
                    que.pop();
                    word_Group += str[i];
                    word_Len += 1;
                    while (!Is_Num(str[i + 1]) && !Is_Engch(str[i + 1]) && i + 1 < lenth)
                    {
                        word_Group += str[i + 1];
                        word_Len += 1;
                        i += 1;
                    }
                    que.push(word_Len);
                    word_Now = "";
                }
            }
            else if (word_Len > 0 && word_Len < 4)              //遇到不合法單詞且不是分隔符或空串的,則返回爲no,將隊列清空
            {
                while (que.empty() != 1)
                {
                    que.pop();
                }
                word_Now = "";
                word_Group = "";
            }
            else if (word_Len == 0)
            {
                continue;
            }                                               //是否要判斷在輸入到函數中
        }
    }
}
  • 性能分析與改進

    • 描述你改進的思路

      在下面所示截圖很容易能夠看出主要是詞組詞頻統計的函數消耗的比較多,程序中消耗最大的函數爲Cut_Ttl_Abs佔50.09%,其次是Word_Group_Cnt函數佔43.59%,點進代碼查看消耗比較大的代碼段是因爲直接或間接使用Is_Word函數,可是Is_Word函數爲每一個單詞斷定是否合法所必需用到的。且從代碼中能夠看出其Is_Word函數中代碼行消耗分佈都很平均,因此暫時不知如何進一步優化改進。
    • 展現性能分析圖和程序中消耗最大的函數

  • 單元測試


測試的函數及其測試數據構造思路:框架

  • LineCount(計算行數):

    構造思路:
    • 中間增長空白行;
    • 當字符串長度大小超過1024,txt則會在視覺上顯示兩行但實際上是一行;
    • 多(十)個測試數據文件防止偶然性
  • WordCount(計算單詞數):

    構造思路:
    • 多種不合法單詞,如123ahkjk,kkk3jkljk,kkk,lll等等;
    • 經過特殊分隔符分隔的一長串單詞視爲兩個單詞,如title-task,github--parent等等;
    • 標題摘要的兩個關鍵字可能不只只在首端「Title:」、「Abstract:」形式出現,後續摘要標題內容也可能存在這兩個單詞;
    • 多(十)個測試數據文件防止偶然性;
  • CharCount(計算字符數):

    構造思路:
    • 編號長度不固定,好比一、2三、97八、97六、46,這些字符統計長度會變化;
    • 兩篇論文間或者論文列表後面有多餘空白行,即不止只有兩行空行時,應該計算其字符數;
    • 多(十)個測試數據文件防止偶然性;
  • IsWord(判斷是否爲合法單詞):

    構造思路:
    • 輸入有大寫字母返回時應將其轉化爲小寫形式輸出;
    • 輸入爲多種不合法單詞,如123,123llllk,kkk,kkk1235,llk2lk等等輸出爲no;
    • 輸入爲空串時返回依舊爲空串;
  • Word_Group_Count(詞組切割統計):

    構造思路:
    • 合法單詞之間可能存在多個分隔符;
    • 合法單詞之間存在不合法單詞;
    • 連續合法單詞個數超過用戶定義組成詞組單詞個數;
    • 同一詞組出現屢次;
  • SortTopNum(對前Num單詞或詞組進行詞頻排序):

    構造思路:
    • 不一樣單詞的數量不一樣;
    • 單詞數量相同可是其字典序不一樣;
    • Num數量變化詞組合法單詞數變化;

對於其餘一些函數,由於在計算行數、計算單詞數、計算字符數、詞組切割統計以及詞頻排序中都有調用,而這些函數測試均正確,所以那些簡易的函數的沒有作出測試,經過複雜函數的正確測試間接反應其正確性。

部分代碼展現:

namespace IsWord        //判斷是不是單詞
{
    TEST_CLASS(UnitTest1)
    {
    public:

        TEST_METHOD(TestMethod1)
        {
            string word = "123ajlk";
            word = Is_Word(word);
            Assert::IsTrue(word == "no");
        }
        TEST_METHOD(TestMethod2)
        {
            string word = "Ajlk";
            word = Is_Word(word);
            Assert::IsTrue(word == "ajlk");
        }
        TEST_METHOD(TestMethod3)
        {
            string word = "Ajl";
            word = Is_Word(word);
            Assert::IsTrue(word == "no");
        }
        TEST_METHOD(TestMethod4)
        {
            string word = "Ajlk123";
            word = Is_Word(word);
            Assert::IsTrue(word == "ajlk123");
        }
        TEST_METHOD(TestMethod5)
        {
            string word = "jl12k23";
            word = Is_Word(word);
            Assert::IsTrue(word == "no");
        }
    };
}

namespace Word_Group_Count      //詞組切割統計
{
    TEST_CLASS(UnitTest1)
    {
    public:

        TEST_METHOD(TestMethod1)
        {
            map<string, int> m;
            Word_Group_Cnt(3, "aaaa bbbb cccc cccc bbbb cccc aaaa dddd cccc bbbb aaaa bbbb cccc dddd", m, 10);

            Assert::IsTrue(m["aaaa bbbb cccc"] == 20 && m["bbbb cccc cccc"] == 10);
        }
        TEST_METHOD(TestMethod2)
        {
            map<string, int> m;
            Word_Group_Cnt(4, "aaaa bbbb cccc dddd bbbb cccc aaaa dddd cccc bbbb aaaa bbbb cccc dddd", m, 10);

            Assert::IsTrue(m["aaaa bbbb cccc dddd"] == 20 && m["bbbb cccc dddd bbbb"] == 10);
        }
        TEST_METHOD(TestMethod3)
        {
            map<string, int> m;
            Word_Group_Cnt(2, "aaaa bbbb cccc cccc bbbb cccc aaaa dddd cccc bbbb aaaa bbbb cccc dddd", m, 10);

            Assert::IsTrue(m["bbbb cccc"] == 30 && m["aaaa bbbb"] == 20);
        }
        TEST_METHOD(TestMethod4)
        {
            map<string, int> m;
            Word_Group_Cnt(5, "aaaa (bbbb) cccc cccc bbbb cccc aaaa dddd cccc bbbb aaaa bbbb cccc dddd", m, 10);

            Assert::IsTrue(m["aaaa (bbbb) cccc cccc bbbb"] == 10 && m["bbbb aaaa bbbb cccc dddd"] == 10);
        }
        TEST_METHOD(TestMethod5)
        {
            map<string, int> m;
            Word_Group_Cnt(6, "aaaa (bbbb)-cccc cccc bbbb cccc aaaa dddd cccc bbbb aaaa bbbb cccc dddd", m, 10);

            Assert::IsTrue(m["aaaa (bbbb)-cccc cccc bbbb cccc"] == 10 && m["aaaa dddd cccc bbbb aaaa bbbb"] == 10);
        }
    };
}

代碼覆蓋率:

  • 貼出Github的代碼簽入記錄


    (兩人提交記錄)

  • 遇到的代碼模塊異常或結對困難及解決方法

① 佩佩

  • 問題描述:

    1. (已解決)詞組切割時題意不清楚,對做業的分隔符也要輸出的要求感受太不友好和助教聯繫請教了一段時間,最終敵不過你們都沒意見,本人勢單力薄,而助教說的投票杳無音信,因而,恭喜本身決定有無分隔符的都寫個函數,這樣便不受影響了;
    2. (已解決)對Title和Abstract進行切割的時候一度覺得滿了txt一行所示的1024個字符便算一行,所以切割時作了許多額外的滿1024個字符考慮行與行之間的拼接組成總的abstract字段,但其實getline就是讀取一行遇到換行符纔會停下;
    3. (已解決)單元測試時遇到模塊計算機x86和目標計算機x64衝突的問題,即庫文件32位和項目文件64位之間存在衝突,一直不能正確測試;
    4. (已解決)在進行測試的時候txt文件首部莫名會添上3個編碼頭字符(隱藏着看不見的),將其編碼改爲UTF-8就行了。
  • 作過哪些嘗試:

    1. 直接須要輸出分隔符和不須要輸出分隔符函數分別寫一個,就不存在這樣的焦慮了,替本身的機智鼓掌!
    2. 最後在作單元測試的時候出現挺多錯誤,進行函數斷點調試時發現原來getline讀取的string直接就達到1058!(而後感慨於本身的sb,分什麼1024)因而對代碼進行修改刪除;
    3. 敲重點!!! 琢磨了一個晚上下午下課至晚上八、9點不間斷4 、5個小時查閱衆多資料和尋求大佬未果(在此謝謝暢暢同窗的分析和幫忙),最終仔細分析其根源,靈感將至,發現原來是obj文件路徑設置的時候,其實建立一個Visual Studio項目會有x64和Debug和WordCount好幾個文件夾,其中.exe和.obj文件在x64文件夾和Debug文件夾中都有,而我定的路徑是Debug中的(我的見解:實際上是32位產生的obj),所以會一直報錯,將路徑修改成x64裏面的obj文件便可;關於這個問題詳情能夠參考我記錄的糾錯博客
    4. 詢問溫柔美麗的助教雨勤姐姐,得知個人問題所在並作出修改。在此謝過雨勤姐姐!!!
  • 有何收穫:
    • 沒有什麼不友好要求,有的只是本身僥倖想方便想偷懶的心理,全部可能要求作一遍就easy soso了;
    • 作單元測試真是一件須要時間,十分重要,任務繁瑣的活,我的認爲單元測試的目的便在於對於不一樣的函數進行多種狀況覆蓋考慮,測試其正確性,而不只僅是爲了完成單元測似的要求每一個函數寫一個簡單的例子測試正確便視做測試完畢;單元測試是能夠幫助確保函數的正確性,項目的正確性。
    • 對於碰到的bug就應該多問多查多試探多琢磨,你會發現老是能解決的,雖然時間花費的不肯定性蠻大(偷笑),這個天然就看手法了;
    • 一直以來都以爲爲何要畫流程圖,流程圖怎麼畫?總以爲很繁瑣和沒有必要,此次從頭畫了一遍流程圖收穫了不少!(固然畫了蠻久)確實流程圖能夠幫助一個即便沒有接觸具體代碼的人也能很快的瞭解實現的思路和框架。而且能夠在本身畫的過程當中幫助理清代碼的邏輯,對本身寫的代碼更清晰的認識。

②沸沸

  • 問題描述:
    (已解決)在附加功能的實現上,咱們一開始爬到了做者和論文pdf網址等信息就止步於此,對更多信息的抓取和分析上產生了困難。
  • 作過哪些嘗試:
    1. 從google學術上意外發現了做者的我的資料,詳盡到有與做者關係密切的其餘做者,咱們所以有了直接爬取現有分析結果的想法。失敗的緣由有不少,主要緣由仍是由於技術問題,做爲剛剛入門python的小白對google的反爬封鎖實在苦手,還有存在做者重名的問題難以檢索,放棄。
    2. 嘗試爬蟲軟件,不會用,失敗。
    3. 爬取做者使用數據分析軟件NodeXL大獲成功,一舉生成關係圖譜。
  • 有何收穫:
    爬蟲能力提高,搜索能力提高

  • 評價你的隊友

胡緒佩

值得學習的地方

佩佩,有太多值得我學習的地方了……好比遇到bug不放棄堅持持續打碼n小時解決,好比遇到問題鑽研求知的精神,好比知難而進的性格,好比在我睡覺的時候把博客發了……好隊友!!!

須要改進的地方

基本上沒有,除了讓我不要偷偷揹着他打代碼hhhhhhh

莊卉

值得學習的地方

沸沸,有太多值得我學習的地方了+1......好比看到項目便知道體諒隊友把難點(附加功能)攬下力肝(卉:表示並無完成得很好),好比寫代碼速度老是莫名其妙超快的不知道有何祕訣!好比善於和隊友溝通交流的團隊精神,解決未知困難的能力plusplus,完美解決了本次做業第一第二做者圖譜的這個難點,好比溫柔美麗的氣質......棒隊友!!!

須要改進的地方

基本上沒有,再有機會緊抱大腿我定牢牢不放xixixixixi

  • 學習進度條

    第N周 新增代碼(行) 累計代碼(行) 本週學習耗時(小時) 累計學習耗時(小時) 重要成長
    1 666 666 15 15 複習c++,學習單元測試和代碼覆蓋率,學習git
    2 97 763 4 19 沒什麼成長,就是在優化代碼
    3 0 0 10 29 閱讀《構建之法》第三章和第八章,學習使用Axure RP8,瞭解原型設計的方法
    4 197 960 20 49 進一步學習爬蟲(瞭解beautifulsoup使用、學會使用正則),學習使用git進行團隊協做,學習使用NodeXL,瞭解flask
相關文章
相關標籤/搜索