一、基本信息
1.1、編譯環境、作者、項目名稱
1 # 編譯環境:Pycharm2017、Python3.7 2 # 項目名稱:詞頻統計——基本功能(結對編程) 3 # 作者:1613072038:夏文傑 4 # 1613072040:高昶
1.2、其他
二、項目分析
2.1 程序運行模塊(方法、函數)介紹(因為代碼大部分和上次作業一樣所以本文中只貼上不同的地方和重要的地方,源碼可以在Git上查看)
-
Task1:基本任務(WordCount.py -(Git上的程序名))
主要需要解決二個問題:1、統計文件的有效行數;2、統計文件的單詞總數(其中特殊定義了單詞的定義);3、將數據存儲在文本中
1、統計文件的有效行數
1 lines = len(open(dst, 'r').readlines()) # 借助readlines可以獲得文本的行數
2、統計文件的單詞總數(其中特殊定義了單詞的定義),這里使用正則表達式。
(參考:http://www.runoob.com/python/python-reg-expressions.html )
1 def process_buffer(bvffer): 2 if bvffer: 3 for ch in ':,.-_': 4 bvffer = bvffer.lower().replace(ch, " ") 5 bvffer = bvffer.strip().split() 6 word_re = "^[a-z]{4}(\w)*" 7 # 正則匹配至少以4個英文字母開頭,跟上字母數字符號,單詞以分隔符分割,不區分大小寫 8 words = [] 9 for i in range(len(bvffer)): 10 word = re.match(word_re, bvffer[i]) # 匹配list中的元素 11 if word: # 匹配成功,加入words 12 words.append(word.group()) 13 word_freq = {} 14 for word in words: # 對words進行統計 15 word_freq[word] = word_freq.get(word, 0) + 1 16 return word_freq, len(words)
3、將數據存儲在文本中
1 def input_result(dst, lines, words, items): # 寫入文件 2 with open(dst, 'w') as w: 3 w.write(lines) 4 w.write(words) 5 for item in items: # 格式化 6 item = '<' + str(item[0]) + '>:' + str(item[1]) + '\n' 7 w.write(item) 8 print('寫入result文件已完成!') 9 w.close()
-
Task2.1:支持停詞(stop_word.py)
這里我們需要建一個存放停詞庫的文本“stopwords.txt”
上圖是停詞庫的部分,然后需要創建一個list存放文本里的停詞,然后在統計詞頻是遍歷list,如果元素存在list中跳過。
1 def process_buffer(bvffer, dst): 2 txt_words = open(dst, 'r').readlines() # 讀取停詞表文件 3 stop_words = [] # 存放停詞表的list 4 for i in range(len(txt_words)): 5 txt_words[i] = txt_words[i].replace('\n', '') 6 # 因為讀取文本是readlines所以寫入list要將換行符取代 7 stop_words.append(txt_words[i]) 8 if bvffer: 9 word_freq = {} # 下面添加處理緩沖區 bvffer代碼,統計每個單詞的頻率,存放在字典word_freq 10 bvffer = bvffer.lower() # 將文本內容都改為小寫 11 for ch in '“‘!;,.?’”': # 除去文本中的中英文標點符號 12 bvffer = bvffer.replace(ch, " ") 13 words = bvffer.strip().split() 14 # strip()刪除空白符(包括'/n', '/r','/t');split()以空格分割字符串 15 for word in words: 16 if word in stop_words: # 如果word在停詞表里就跳過(本任務核心) 17 continue 18 else: 19 word_freq[word] = word_freq.get(word, 0) + 1 20 return word_freq
-
Task2.2:查看常用的短語(phrase.py)
此處我和搭檔夏文傑,都有自己不同的想法。夏文傑的想法是:將以空格分割字符后的list為對象。創建新的字符串(list[i]+' '+list[i+1])組成我們想要的短語;我的想法是用正則表達式來匹配我們想要的短語。我們各自執行了自己的想法,因為夏同學的想法要多次遍歷數組所以會很耗時,所以我們決定選用正則表達式匹配的方法。
1 # 正則表達式 2 two_phrase_re = '[a-z]+\s[a-z]+' # 匹配二個單詞的短語 3 three_phrase_re = '[a-z]+\s[a-z]+\s[a-z]+' # 匹配三個單詞的短語
但是我們發現結果並不讓人滿意,輸出的結果都是:“There be”、“I‘m’”、“It was”、“She was”等沒有達到我們想要的,所以我們想到結合停詞來改善項目。
1 def create_stop_words(dst): # 創建停詞表 2 txt_words = open(dst, encoding='utf-8').readlines() # 文本讀取 3 phrase_words = [] # 存放停詞表的list 4 for i in range(len(txt_words)): 5 txt_words[i] = txt_words[i].replace('\n', '') 6 # 因為讀取文本是readlines所以寫入list要將換行符取代 7 phrase_words.append(txt_words[i]) 8 return phrase_words
1 def process_buffer(dst, phrase_words, regex): 2 words = open(dst, 'r').read() # 文本讀取 3 bvffer = words.lower() # 將文本內容都改為小寫 4 # 將文本中的縮寫都替換(進過程序發現以下是最常見的) 5 bvffer = bvffer.replace('’t', '') 6 bvffer = bvffer.replace('’m', '') 7 bvffer = bvffer.replace('’s', '') 8 bvffer = bvffer.replace('’ve', '') 9 # 其實上面的替換可以防在停詞中但是涉及到空格等問題就放在前面直接替換了 10 for i in range(len(phrase_words)): # 將文本中的“停詞”刪除掉,這樣會使結果很清晰更能接受 11 bvffer = bvffer.replace(' ' + phrase_words[i] + ' ', ' ') 12 result = re.findall(regex, bvffer) # 正則查找詞組 13 word_freq = {} 14 for word in result: # 將正則匹配的結果進行統計 15 word_freq[word] = word_freq.get(word, 0) + 1 16 return word_freq
當然我們在學習的過程中還了解到了jieba、nltk。我們也嘗試了用nltk庫進行分詞等處理。也寫了個半成品,具體代碼可以查看Git上的(NLTK.py)。
2.2、程序算法的時間、空間復雜度分析
此處我們以以下代碼為例:
1 def process_buffer(dst, phrase_words, regex): 2 words = open(dst, 'r').read() # 文本讀取 3 bvffer = words.lower() # 將文本內容都改為小寫 4 # 將文本中的縮寫都替換(進過程序發現以下是最常見的) 5 bvffer = bvffer.replace('’t', '') 6 bvffer = bvffer.replace('’m', '') 7 bvffer = bvffer.replace('’s', '') 8 bvffer = bvffer.replace('’ve', '') 9 # 其實上面的替換可以防在停詞中但是涉及到空格等問題就放在前面直接替換了 10 for i in range(len(phrase_words)): # 將文本中的“停詞”刪除掉,這樣會使結果很清晰更能接受 11 bvffer = bvffer.replace(' ' + phrase_words[i] + ' ', ' ') 12 result = re.findall(regex, bvffer) # 正則查找詞組 13 word_freq = {} 14 for word in result: # 將正則匹配的結果進行統計 15 word_freq[word] = word_freq.get(word, 0) + 1 16 return word_freq
函數process_buffer中:時間復雜度關注二個for循環就行,假設文本中有N個單詞,result中的元素個數為n,其中(N>n),所以時間復雜度為O(N+n),空間復雜度,即需要的輔助空間大小,即word_freq = {}的長度,所以空間復雜度為O(2n)。其他部分分析一樣,就不多加贅述了。
2.3、程序運行案例截圖
-
Task:基本任務(WordCount.py)
其中測試文件:‘test.txt’:
WordCount.py的運行結果:
-
Task2.1:支持停詞(stop_word.py)
我們發現我們的詞頻統計里沒有了我們停詞表里的詞。
-
Task2.2:查看常用的短語(phrase.py)
二個單詞的短語:
三個單詞的短語:
三、性能分析
我們大概花了一半的時間在提高程序性能上,大部分都花在改進算法上,比如前面提到的如何實現Task2.2。經過我們的改進,項目基本達到我們的預期。
附上:Task2.2的運行時間的截圖和性能表。(整個程序運行時間在一秒左右)
四、其他
-
結對編程時間開銷:二人也經過大概半個星期的研究、討論,實際結對開發編程大概在5小時左右。
-
結對編程照片
四、事后分析與總結
-
簡述結對編程時,針對某個問題的討論決策過程。
如Task2.2中 ,我和搭檔夏文傑,都有自己不同的想法。夏文傑的想法是:將以空格分割字符后的list為對象。創建新的字符串(list[i]+' '+list[i+1])組成我們想要的短語;我的想法是用正則表達式來匹配我們想要的短語。我們各自執行了自己的想法,因為夏同學的想法要多次遍歷數組所以會很耗時,所以我們決定選用正則表達式匹配的方法。遇到有爭議的地方我們就各種完成自己的想法,然后比較性能,誰好用誰的。
- 評價對方:請評價一下你的合作伙伴,又哪些具體的優點和需要改進的地方。 這個部分兩人都要提供自己的看法。
高昶評價夏文傑:夏文傑很有悟性,我提出他不理解的東西,他能很快的理解,然后通過他的理解運用到程序中。需要改進的地方:知識面不是很廣,平時還需要多閱讀、了解計算機相關的知識。
夏文傑評價高昶:高昶有很豐富的編程經驗,能很快的想到解決問題的辦法,並能很好的實施。需要改進的地方:對知識掌握不牢固,很容易將知識混淆,所以希望能夠將鞏固一下自己的知識並與經驗相結合。
- 評價整個過程:關於結對過程的建議
結對編程是一個相互學習、相互磨合的漸進過程,因為二人平時關系就很不錯,二人都很認真的完成本次任務,所以本次的結對編程是很愉快的。通過本次結對編程我們也充分的認識到了合作的重要性,一個人編程不免要犯這樣那樣的錯誤,結對編程就很好的避免了這樣的問題,而且二人會碰撞出更多的想法和靈感,二人相互學習,相互補充。而且結對編程能提供更好的設計質量和代碼質量,兩人合作能有更強的解決問題的能力。還有就是,結對編程讓有些許枯燥的編程,變得有趣。
建議:結對編程是一件很不錯的事情,但是結對編程的過程中難免發生爭執,所以妥善處理好爭議才能更好的將結對編程做好。
- 其它
建議下次的結對編程不需要給出固定的題目,讓結對的人自由發揮!