中文文字挖掘預處理流程總結

劉建平Pinard發表於2017-04-21

    在對文字做資料分析時,我們一大半的時間都會花在文字預處理上,而中文和英文的預處理流程稍有不同,本文就對中文文字挖掘的預處理流程做一個總結。

1. 中文文字挖掘預處理特點

    首先我們看看中文文字挖掘預處理和英文文字挖掘預處理相比的一些特殊點。

    首先,中文文字是沒有像英文的單詞空格那樣隔開的,因此不能直接像英文一樣可以直接用最簡單的空格和標點符號完成分詞。所以一般我們需要用分詞演算法來完成分詞,在文字挖掘的分詞原理中,我們已經講到了中文的分詞原理,這裡就不多說。

    第二,中文的編碼不是utf8,而是unicode。這樣會導致在分詞的時候,和英文相比,我們要處理編碼的問題。

    這兩點構成了中文分詞相比英文分詞的一些不同點,後面我們也會重點講述這部分的處理。當然,英文分詞也有自己的煩惱,這個我們在以後再講。瞭解了中文預處理的一些特點後,我們就言歸正傳,通過實踐總結下中文文字挖掘預處理流程。

2.  中文文字挖掘預處理一:資料收集

    在文字挖掘之前,我們需要得到文字資料,文字資料的獲取方法一般有兩種:使用別人做好的語料庫和自己用爬蟲去在網上去爬自己的語料資料。

    對於第一種方法,常用的文字語料庫在網上有很多,如果大家只是學習,則可以直接下載下來使用,但如果是某些特殊主題的語料庫,比如“機器學習”相關的語料庫,則這種方法行不通,需要我們自己用第二種方法去獲取。

    對於第二種使用爬蟲的方法,開源工具有很多,通用的爬蟲我一般使用beautifulsoup。但是我們我們需要某些特殊的語料資料,比如上面提到的“機器學習”相關的語料庫,則需要用主題爬蟲(也叫聚焦爬蟲)來完成。這個我一般使用ache。 ache允許我們用關鍵字或者一個分類演算法來過濾出我們需要的主題語料,比較強大。

3.  中文文字挖掘預處理二:除去資料中非文字部分

    這一步主要是針對我們用爬蟲收集的語料資料,由於爬下來的內容中有很多html的一些標籤,需要去掉。少量的非文字內容的可以直接用Python的正規表示式(re)刪除, 複雜的則可以用beautifulsoup來去除。去除掉這些非文字的內容後,我們就可以進行真正的文字預處理了。

4. 中文文字挖掘預處理三:處理中文編碼問題

    由於Python2不支援unicode的處理,因此我們使用Python2做中文文字預處理時需要遵循的原則是,儲存資料都用utf8,讀出來進行中文相關處理時,使用GBK之類的中文編碼,在下面一節的分詞時,我們再用例子說明這個問題。

5. 中文文字挖掘預處理四:中文分詞

    常用的中文分詞軟體有很多,個人比較推薦結巴分詞。安裝也很簡單,比如基於Python的,用"pip install jieba"就可以完成。下面我們就用例子來看看如何中文分詞。

    完整程式碼參見我的github: https://github.com/ljpzzz/machinelearning/blob/master/natural-language-processing/chinese_digging.ipynb

    首先我們準備了兩段文字,這兩段文字在兩個檔案中。兩段文字的內容分別是nlp_test0.txt和nlp_test2.txt:

          沙瑞金讚歎易學習的胸懷,是金山的百姓有福,可是這件事對李達康的觸動很大。易學習又回憶起他們三人分開的前一晚,大家一起喝酒話別,易學習被降職到道口縣當縣長,王大路下海經商,李達康連連賠禮道歉,覺得對不起大家,他最對不起的是王大路,就和易學習一起給王大路湊了5萬塊錢,王大路自己東挪西撮了5萬塊,開始下海經商。沒想到後來王大路竟然做得風生水起。沙瑞金覺得他們三人,在困難時期還能以沫相助,很不容易。

    沙瑞金向毛婭打聽他們家在京州的別墅,毛婭笑著說,王大路事業有成之後,要給歐陽菁和她公司的股權,她們沒有要,王大路就在京州帝豪園買了三套別墅,可是李達康和易學習都不要,這些房子都在王大路的名下,歐陽菁好像去住過,毛婭不想去,她覺得房子太大很浪費,自己家住得就很踏實。

   我們先講文字從第一個檔案中讀取,並使用中文GBK編碼,再呼叫結巴分詞,最後把分詞結果用uft8格式存在另一個文字nlp_test1.txt

中。程式碼如下:

# -*- coding: utf-8 -*-

import jieba

with open('./nlp_test0.txt') as f:
    document = f.read()
    
    document_decode = document.decode('GBK')
    document_cut = jieba.cut(document_decode)
    #print  ' '.join(jieba_cut)  //如果列印結果,則分詞效果消失,後面的result無法顯示
    result = ' '.join(document_cut)
    result = result.encode('utf-8')
    with open('./nlp_test1.txt', 'w') as f2:
        f2.write(result)
f.close()
f2.close()

    輸出的文字內容如下:

    沙 瑞金 讚歎 易 學習 的 胸懷 , 是 金山 的 百姓 有福 , 可是 這件 事對 李達康 的 觸動 很大 。 易 學習 又 回憶起 他們 三人 分開 的 前一晚 , 大家 一起 喝酒 話別 , 易 學習 被 降職 到 道口 縣當 縣長 , 王 大路 下海經商 , 李達康 連連 賠禮道歉 , 覺得 對不起 大家 , 他 最 對不起 的 是 王 大路 , 就 和 易 學習 一起 給 王 大路 湊 了 5 萬塊 錢 , 王 大路 自己 東挪西撮 了 5 萬塊 , 開始 下海經商 。 沒想到 後來 王 大路 竟然 做 得 風生水 起 。 沙 瑞金 覺得 他們 三人 , 在 困難 時期 還 能 以沫 相助 , 很 不 容易 。

    可以發現對於一些人名和地名,jieba處理的不好,不過我們可以幫jieba加入詞彙如下:

jieba.suggest_freq('沙瑞金', True)
jieba.suggest_freq('易學習', True)
jieba.suggest_freq('王大路', True)
jieba.suggest_freq('京州', True)

    現在我們再來進行讀檔案,編碼,分詞,編碼和寫檔案,程式碼如下:

with open('./nlp_test0.txt') as f:
    document = f.read()
    
    document_decode = document.decode('GBK')
    document_cut = jieba.cut(document_decode)
    #print  ' '.join(jieba_cut)
    result = ' '.join(document_cut)
    result = result.encode('utf-8')
    with open('./nlp_test1.txt', 'w') as f2:
        f2.write(result)
f.close()
f2.close()   

    輸出的文字內容如下:

    沙瑞金 讚歎 易學習 的 胸懷 , 是 金山 的 百姓 有福 , 可是 這件 事對 李達康 的 觸動 很大 。 易學習 又 回憶起 他們 三人 分開 的 前一晚 , 大家 一起 喝酒 話別 , 易學習 被 降職 到 道口 縣當 縣長 , 王大路 下海經商 , 李達康 連連 賠禮道歉 , 覺得 對不起 大家 , 他 最 對不起 的 是 王大路 , 就 和 易學習 一起 給 王大路 湊 了 5 萬塊 錢 , 王大路 自己 東挪西撮 了 5 萬塊 , 開始 下海經商 。 沒想到 後來 王大路 竟然 做 得 風生水 起 。 沙瑞金 覺得 他們 三人 , 在 困難 時期 還 能 以沫 相助 , 很 不 容易 。

    基本已經可以滿足要求。同樣的方法我們對第二段文字nlp_test2.txt進行分詞和寫入檔案nlp_test3.txt。

with open('./nlp_test2.txt') as f:
    document2 = f.read()
    
    document2_decode = document2.decode('GBK')
    document2_cut = jieba.cut(document2_decode)
    #print  ' '.join(jieba_cut)
    result = ' '.join(document2_cut)
    result = result.encode('utf-8')
    with open('./nlp_test3.txt', 'w') as f2:
        f2.write(result)
f.close()
f2.close()  

    輸出的文字內容如下:

    沙瑞金 向 毛婭 打聽 他們 家 在 京州 的 別墅 , 毛婭 笑 著 說 , 王大路 事業有成 之後 , 要 給 歐陽 菁 和 她 公司 的 股權 , 她們 沒有 要 , 王大路 就 在 京州 帝豪園 買 了 三套 別墅 , 可是 李達康 和 易學習 都 不要 , 這些 房子 都 在 王大路 的 名下 , 歐陽 菁 好像 去 住 過 , 毛婭 不想 去 , 她 覺得 房子 太大 很 浪費 , 自己 家住 得 就 很 踏實 。

    可見分詞效果還不錯。

6. 中文文字挖掘預處理五:引入停用詞

    在上面我們解析的文字中有很多無效的詞,比如“著”,“和”,還有一些標點符號,這些我們不想在文字分析的時候引入,因此需要去掉,這些詞就是停用詞。常用的中文停用詞表是1208個,下載地址在這。當然也有其他版本的停用詞表,不過這個1208詞版是我常用的。

    在我們用scikit-learn做特徵處理的時候,可以通過引數stop_words來引入一個陣列作為停用詞表。

    現在我們將停用詞表從檔案讀出,並切分成一個陣列備用:

#從檔案匯入停用詞表
stpwrdpath = "stop_words.txt"
stpwrd_dic = open(stpwrdpath, 'rb')
stpwrd_content = stpwrd_dic.read()
#將停用詞表轉換為list  
stpwrdlst = stpwrd_content.splitlines()
stpwrd_dic.close()

7. 中文文字挖掘預處理六:特徵處理

    現在我們就可以用scikit-learn來對我們的文字特徵進行處理了,在文字挖掘預處理之向量化與Hash Trick中,我們講到了兩種特徵處理的方法,向量化與Hash Trick。而向量化是最常用的方法,因為它可以接著進行TF-IDF的特徵處理。在文字挖掘預處理之TF-IDF中,我們也講到了TF-IDF特徵處理的方法。這裡我們就用scikit-learn的TfidfVectorizer類來進行TF-IDF特徵處理。

    TfidfVectorizer類可以幫助我們完成向量化,TF-IDF和標準化三步。當然,還可以幫我們處理停用詞。

    現在我們把上面分詞好的文字載入記憶體:

with open('./nlp_test1.txt') as f3:
    res1 = f3.read()
print res1
with open('./nlp_test3.txt') as f4:
    res2 = f4.read()
print res2

    這裡的輸出還是我們上面分完詞的文字。現在我們可以進行向量化,TF-IDF和標準化三步處理了。注意,這裡我們引入了我們上面的停用詞表。

from sklearn.feature_extraction.text import TfidfVectorizer
corpus = [res1,res2]
vector = TfidfVectorizer(stop_words=stpwrdlst)
tfidf = vector.fit_transform(corpus)
print tfidf

    部分輸出如下:

  (0, 44)	0.154467434933
  (0, 59)	0.108549295069
  (0, 39)	0.308934869866
  (0, 53)	0.108549295069
  ....
  (1, 27)	0.139891059658
  (1, 47)	0.139891059658
  (1, 30)	0.139891059658
  (1, 60)	0.139891059658

    我們再來看看每次詞和TF-IDF的對應關係:

wordlist = vector.get_feature_names()#獲取詞袋模型中的所有詞  
# tf-idf矩陣 元素a[i][j]表示j詞在i類文字中的tf-idf權重
weightlist = tfidf.toarray()  
#列印每類文字的tf-idf詞語權重,第一個for遍歷所有文字,第二個for便利某一類文字下的詞語權重
for i in range(len(weightlist)):  
    print "-------第",i,"段文字的詞語tf-idf權重------"  
    for j in range(len(wordlist)):  
        print wordlist[j],weightlist[i][j]  

    部分輸出如下:

-------第 0 段文字的詞語tf-idf權重------
一起 0.217098590137
萬塊 0.217098590137
三人 0.217098590137
三套 0.0
下海經商 0.217098590137
.....
-------第 1 段文字的詞語tf-idf權重------
.....
李達康 0.0995336411066
歐陽 0.279782119316
毛婭 0.419673178975
沙瑞金 0.0995336411066
沒想到 0.0
沒有 0.139891059658
浪費 0.139891059658
王大路 0.29860092332
.....

 

8. 中文文字挖掘預處理七:建立分析模型

    有了每段文字的TF-IDF的特徵向量,我們就可以利用這些資料建立分類模型,或者聚類模型了,或者進行主題模型的分析。比如我們上面的兩段文字,就可以是兩個訓練樣本了。此時的分類聚類模型和之前講的非自然語言處理的資料分析沒有什麼兩樣。因此對應的演算法都可以直接使用。而主題模型是自然語言處理比較特殊的一塊,這個我們後面再單獨講。

9.中文文字挖掘預處理總結

    上面我們對中文文字挖掘預處理的過程做了一個總結,希望可以幫助到大家。需要注意的是這個流程主要針對一些常用的文字挖掘,並使用了詞袋模型,對於某一些自然語言處理的需求則流程需要修改。比如我們涉及到詞上下文關係的一些需求,此時不能使用詞袋模型。而有時候我們對於特徵的處理有自己的特殊需求,因此這個流程僅供自然語言處理入門者參考。

    下一篇我們來總結英文文字挖掘預處理流程,盡情期待。

 

(歡迎轉載,轉載請註明出處。歡迎溝通交流: liujianping-ok@163.com) 

相關文章