在對文本作數據分析時,咱們一大半的時間都會花在文本預處理上,而中文和英文的預處理流程稍有不一樣,本文就對中文文本挖掘的預處理流程作一個總結。html
首先咱們看看中文文本挖掘預處理和英文文本挖掘預處理相比的一些特殊點。git
首先,中文文本是沒有像英文的單詞空格那樣隔開的,所以不能直接像英文同樣能夠直接用最簡單的空格和標點符號完成分詞。因此通常咱們須要用分詞算法來完成分詞,在文本挖掘的分詞原理中,咱們已經講到了中文的分詞原理,這裏就很少說。github
第二,中文的編碼不是utf8,而是unicode。這樣會致使在分詞的時候,和英文相比,咱們要處理編碼的問題。正則表達式
這兩點構成了中文分詞相比英文分詞的一些不一樣點,後面咱們也會重點講述這部分的處理。固然,英文分詞也有本身的煩惱,這個咱們在之後再講。瞭解了中文預處理的一些特色後,咱們就言歸正傳,經過實踐總結下中文文本挖掘預處理流程。算法
在文本挖掘以前,咱們須要獲得文本數據,文本數據的獲取方法通常有兩種:使用別人作好的語料庫和本身用爬蟲去在網上去爬本身的語料數據。數組
對於第一種方法,經常使用的文本語料庫在網上有不少,若是你們只是學習,則能夠直接下載下來使用,但若是是某些特殊主題的語料庫,好比「機器學習」相關的語料庫,則這種方法行不通,須要咱們本身用第二種方法去獲取。機器學習
對於第二種使用爬蟲的方法,開源工具備不少,通用的爬蟲我通常使用beautifulsoup。可是咱們咱們須要某些特殊的語料數據,好比上面提到的「機器學習」相關的語料庫,則須要用主題爬蟲(也叫聚焦爬蟲)來完成。這個我通常使用ache。 ache容許咱們用關鍵字或者一個分類算法來過濾出咱們須要的主題語料,比較強大。工具
這一步主要是針對咱們用爬蟲收集的語料數據,因爲爬下來的內容中有不少html的一些標籤,須要去掉。少許的非文本內容的能夠直接用Python的正則表達式(re)刪除, 複雜的則能夠用beautifulsoup來去除。去除掉這些非文本的內容後,咱們就能夠進行真正的文本預處理了。post
因爲Python2不支持unicode的處理,所以咱們使用Python2作中文文本預處理時須要遵循的原則是,存儲數據都用utf8,讀出來進行中文相關處理時,使用GBK之類的中文編碼,在下面一節的分詞時,咱們再用例子說明這個問題。學習
經常使用的中文分詞軟件有不少,我的比較推薦結巴分詞。安裝也很簡單,好比基於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()
輸出的文本內容以下:
沙瑞金 向 毛婭 打聽 他們 家 在 京州 的 別墅 , 毛婭 笑 着 說 , 王大路 事業有成 以後 , 要 給 歐陽 菁 和 她 公司 的 股權 , 她們 沒有 要 , 王大路 就 在 京州 帝豪園 買 了 三套 別墅 , 但是 李達康 和 易學習 都 不要 , 這些 房子 都 在 王大路 的 名下 , 歐陽 菁 好像 去 住 過 , 毛婭 不想 去 , 她 以爲 房子 太大 很 浪費 , 本身 家住 得 就 很 踏實 。
可見分詞效果還不錯。
在上面咱們解析的文本中有不少無效的詞,好比「着」,「和」,還有一些標點符號,這些咱們不想在文本分析的時候引入,所以須要去掉,這些詞就是停用詞。經常使用的中文停用詞表是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()
如今咱們就能夠用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 .....
有了每段文本的TF-IDF的特徵向量,咱們就能夠利用這些數據創建分類模型,或者聚類模型了,或者進行主題模型的分析。好比咱們上面的兩段文本,就能夠是兩個訓練樣本了。此時的分類聚類模型和以前講的非天然語言處理的數據分析沒有什麼兩樣。所以對應的算法均可以直接使用。而主題模型是天然語言處理比較特殊的一塊,這個咱們後面再單獨講。
上面咱們對中文文本挖掘預處理的過程作了一個總結,但願能夠幫助到你們。須要注意的是這個流程主要針對一些經常使用的文本挖掘,並使用了詞袋模型,對於某一些天然語言處理的需求則流程須要修改。好比咱們涉及到詞上下文關係的一些需求,此時不能使用詞袋模型。而有時候咱們對於特徵的處理有本身的特殊需求,所以這個流程僅供天然語言處理入門者參考。
下一篇咱們來總結英文文本挖掘預處理流程,盡情期待。
(歡迎轉載,轉載請註明出處。歡迎溝通交流: liujianping-ok@163.com)