2014年7月13日 星期日

[Python] 土炮自製文字探勘(TEXT MINING) N-GRAM演算法

        先前在做文字探勘的時候([R] TEXT MINING(文字探勘練習)),主要會用到tmcn以及Rwordseg這兩個套件,這兩個套件主要是運用字典檔的方式將字詞切開,然後再對於切出來的字詞作次數分配,這樣的作法雖然可以清楚切出常用的詞彙,但是也礙於字典檔的限制,無法一些新的、或特別的術語(例如PTT中的詞彙、或是一些講話的口頭禪)。


        因此有人提出了N-GRAM的演算法,這個演算法其實就是一種馬可夫模型,主要用來計算同樣類型的事件依序發生的機率,例如昨天與今天、後天天氣的關係(引自:Google 搜尋預測、拼字檢查、與即時翻譯背後的統計模型:N-Gram) 那運用在文字上,我們就可以觀察不同單字前後的關係。

        中文字是方塊字,一個字有獨立的意思,但是基本上我們講話的時候還是以兩個字以上組合的"詞彙"作為單位,N-GRAM模型主要特點可以用來觀察兩個字一組、三個字一組、或四個字、五個字一組的詞彙出現的機率。我們根據這個想法來設計演算法。選擇PYTHON而不用R的原因在於PYTHON對於字串的處理相對簡單,而且程式碼看起來也會比R直覺。

import codecs
#處理編碼的套件
import operator
##處理字典檔排序的套件
text = codecs.open("text.txt","r","utf-8")
#讀取存成TXT檔的文字,讀入後統一轉成UTF-8格式
text_new =""
for line in text.readlines():
text_new += "".join(line.split('\n'))
#在這邊先做一個小處理,把不同行的文章串接再一起,如果未來要做一些去除標點符號的處理也會是在這邊。
def ngram(text,n): #第一個參數放處理好的文章,第二個參數放字詞的長度單位
words=[] #存放擷取出來的字詞
words_freq={}#存放字詞:計算個數
for w in range(len(text)-(n-1)): #要讀取的長度隨字詞長度改變
words.append(text[w:w+n]) #抓取長度w-(n-1)的字串
for word in words:
if word not in words_freq: #如果這個字詞還沒有被放在字典檔中
words_freq[word] = words.count(word) #就開一個新的字詞,裡面放入字詞計算的頻次
words_freq = sorted(words_freq.iteritems(),key=operator.itemgetter(1),reverse=True) #change words_freq from dict to list
return words_freq
words_freqs = ngram(text_new,3)
for i in words_freqs:
print i[0],i[1]
'''
道:" 35
笑道: 13
"那僧 9
聽了, 8
"士隱 8
。士隱 7
。"那 7
那僧道 6
....
'''
words_freqs = ngram(text_new,2)
for i in words_freqs:
print i[0],i[1]
'''
:" 45
道: 36
士隱 33
雨村 25
,不 24
。" 22
那僧 17
,便 16
...
'''
view raw gistfile1.py hosted with ❤ by GitHub
這個演算法中間遇到最大困難在我搞不定unicode的轉換...演算法本身所花時間可能一小時不到吧,但是unicode轉換就花了3小時up...。然後目前還沒有去除標點符號,未來也會將這功能加上去(但是我覺得加上標點符號是必要的,因為中文適用標點斷句,通常標點前後的文字不會形成字詞關係) 另外台灣的文章內容常常中英混打,也是未來要努力的項目。

未來更新重點:
1. 將標點符號視為句子間的分格符號,每一句獨立分析字詞頻次。
2. 將中文英文分開來辨識,中文是用一個"字"作為基本單位,英文是用一個"單字"

參考資料:
演算法筆記
How to Use UTF-8 with Python
協助解決 Google 難題的資訊萃取機制




6 則留言:

  1. nice article! thank you very much!

    回覆刪除
  2. nice article! thank you very much!

    回覆刪除
  3. 請問R方面有相關library嗎
    有許多詞彙用tmcn等等切割是錯誤的
    不知有沒有類似演算法能自己切割正確

    回覆刪除