自然語言處理——中文文本預處理
近期,在自學自然語言處理,初次接觸NLP覺得十分的難,各種概念和算法,而且也沒有很強的編程基礎,學着稍微有點吃力。不過經過兩個星期的學習,已經掌握了一些簡單的中文、英文語料的預處理操作。寫點筆記,記錄一下學習的過程。
1、中文語料的特點
第一點:中文語料中詞與詞之間是緊密相連的,這一點不同與英文或者其它語種的語料,因此在分詞的時候不能像英文使用空格分詞,可以jieba庫進行分詞。第二點:編碼問題,中文語料的編碼格式是unicode,而不是utf-8編碼格式。這里介紹utf-8編碼和unicode編碼讀取的區別,unicode 一個中文字符占2個字節,而UTF-8一個中文字符占3個字節,因此如果不注意編碼問題,在處理過程中肯定會出錯的。
2、中文語料預處理
本次我做的中文語料預處理包含了以下操作:數據導入、數據清洗、中文分詞、去停用詞、特征處理(TF-IDF權重計算)。下面我將模塊介紹我的處理過程。
2.1 數據導入
首先,先准備好本次要使用的數據集,一段摘自騰訊體育新聞中新聞報道,文本保存格式設置為utf-8。然后倒入進python,使用到open函數讀取文件,讀取格式選擇‘r'表示讀取文件,編碼encoding = ’utf-8',查看文件中的內容用read函數。具體編碼如下:
#文件讀取 def read_txt (filepath): file = open(filepath,'r',encoding='utf-8') txt = file.read() return txt
讀取結果展示:
(注意:返回的txt是str類型的,即字符串類型,不需要decode。str與bytes表示的是兩種數據類型,str為字符串型,bytes為字節型。對str編碼encode得到bytes,對bytes解碼decode得到str)
2.2 數據清洗
新聞文本數據中不僅包括了中文字符,還包括了數字、英文字符、標點等非常規字符,這些都是無意義,並且需要處理的數據。清洗的方法使用的是正則表達式,匹配規則為:[\u4e00-\u9fa5],\un匹配n,其中n是一個用四個十六進制數字表示的Unicode字符,而4e00-9fa5之間的Unicode編碼表示的是20000多個中文字符。具體編碼如下:
#匹配[^\u4e00-\u9fa5] def find_chinese (file): pattern = re.compile(r'[^\u4e00-\u9fa5]') chinese_txt = re.sub(pattern,'',file) return chinese_txt
解釋:[\u4e00-\u9fa5]表示匹配漢字,[^\u4e00-\u9fa5]表示匹配除漢字以外的所有字符。
數據展示:
2.3 中文分詞
分詞是中文文本分析的重要內容,正確的分詞可以幫助我們更好的構建模型、運用算法分析。中文分詞一般使用jieba庫中的cut方法,cut方法分詞有兩種模式,一種為全模式,另一種為精准模式,相較於全模式,精准模式分詞更加精准可靠,因此選用精准模式對文本分詞。注:精准模式和全模式的區別在於是否cut_all,精准模式選擇cut_all= False;全模式選擇cut_all= True。Jieba庫的安裝十分簡單,只需要在命令框中輸入:pip install jieba 即可安裝。
import jieba txt = ''' 騰訊體育3月6日訊 史蒂芬-庫里時隔127天后復出,勇士113-121不敵猛龍。猛龍本場比賽過后,取得44勝18負戰績,鎖定季后賽,成為本賽季聯盟第2支鎖定季后賽的球隊,第1支是雄鹿。 比賽開始后,庫里持球組織進攻,明顯改變了猛龍的防守,給克里斯和維金斯創造了輕松得分的機會。但在第一節還剩6分11秒下場時,庫里沒有得分,2次三分出手全部偏出。 但在第二節比賽重新登場后,我們看到了那個熟悉的庫里。他接球投三分命中,迎着防守人超遠壓哨三分命中,第三節還迎着洛瑞完成3+1。那個三分之王和2次常規賽MVP風采依舊。 勇士將士就像打不死的小強,從第一節開始就非常頑強,緊緊的咬住比分,甚至伺機反撲。''' #全模式 jieba_list = jieba.cut(txt,cut_all=True) jieba_txt1 = ' '.join(jieba_list) print('全模式分詞:',jieba_txt1) #精准模式 jieba_list = jieba.cut(txt, cut_all=False) jieba_txt2 = ' ' .join(jieba_list) print('精准模式分詞:',jieba_txt2)
通過這段代碼我們可以體會一下全模式分詞和精准模式分詞的區別。
需要注意的一點是jieba分詞后返回的數據類型是generator類型,是一個迭代器,需要使用for循環才能讀取其中的內容。
處理的算法:
#中文分詞 def cut_word(text): # 精准模式 jieba_list = jieba.cut(text, cut_all=False) return jieba_txt
分詞結果:
2.4 停用詞去除
無論是中文中,還是英文中,都有用來起連接作用的連詞、虛詞、語氣詞等無意義的詞,這些詞沒有具體的含義,只是起着銜接句子的作用。這些詞對文本分析沒有任何幫助,因此我們還需要對分詞后的數據做停用詞處理。進行停用詞處理需要停用詞表,本文中選用的停用詞表為哈工大的停用詞表,因為在國內研究自然語言處理他們屬於翹楚。
停用詞表在我的博客中有分享,有需要的可以自行下載。具體代碼如下:
#去除停用詞 def seg_sentence(list_txt): #讀取停用詞表 stopwords = stopwords = read_txt('哈工大停用詞表.txt') seg_txt = [ w for w in list_txt if w not in stopwords] return seg_txt
去停用詞結果:
2.5 詞頻統計
統計分詞后文本的詞頻,目的是找出對文本影響最重要的詞匯,統計這些詞的頻率可以幫助我們了解文章重點強調了什么,以及方便后續構建模型。詞頻統計中使用了python自帶的collections庫中的counter接口,它可以幫助統計詞頻率。Collection安裝方法:pip install collections。具體代碼:
#詞頻統計 def counter(txt): seg_list = txt c = Counter() for w in seg_list: if w is not ' ': c[w] += 1 return c
統計結果如下所示:
2.6 特征選擇—TF-IDF權重計算
TF-IDF權重是很可靠的權重表征方式,用以評估一字詞對於一個文件集或一個語料庫中的其中一份文件的重要程度。字詞的重要性隨着它在文件中出現的次數成正比增加,但同時會隨着它在語料庫中出現的頻率成反比下降。TF-IDF加權的各種形式常被搜索引擎應用,作為文件與用戶查詢之間相關程度的度量或評級。代碼:
#TF_IDF計算 def tf_idf(txt): corpus_txt = [' '.join(txt)] stopword_list = read_txt(r'哈工大停用詞表.txt').splitlines() vector = TfidfVectorizer(stop_words=stopword_list) tfidf = vector.fit_transform(corpus_txt) print(tfidf) # 獲取詞袋模型中的所有詞 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] )
運行結果:
2.7 總結
到此中文文本的預處理就結束了。暫時這兩個星期學到的預處理就這么多,如有不當之處,還忘大佬能不吝指導。最后附上全部代碼:
import nltk import jieba import re from collections import Counter from sklearn.feature_extraction.text import TfidfVectorizer #創建去除非中文字符的函數 #數據清洗,去除標點符號,數字,等其它非中文字符 #匹配[^\u4e00-\u9fa5] def find_chinese (file): pattern = re.compile(r'[^\u4e00-\u9fa5]') chinese_txt = re.sub(pattern,'',file) return chinese_txt #文件讀取 def read_txt (filepath): file = open(filepath,'r',encoding='utf-8') txt = file.read() return txt #中文分詞 def cut_word(text): # 精准模式 jieba_list = jieba.cut(text, cut_all=False) return jieba_list #去除停用詞 def seg_sentence(list_txt): #讀取停用詞表 stopwords = stopwords = read_txt('哈工大停用詞表.txt') seg_txt = [ w for w in list_txt if w not in stopwords] return seg_txt #詞頻統計 def counter(txt): seg_list = txt c = Counter() for w in seg_list: if w is not ' ': c[w] += 1 return c #TF_IDF計算 def tf_idf(txt): corpus_txt = [' '.join(txt)] stopword_list = read_txt(r'哈工大停用詞表.txt').splitlines() vector = TfidfVectorizer(stop_words=stopword_list) tfidf = vector.fit_transform(corpus_txt) print(tfidf) # 獲取詞袋模型中的所有詞 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] ) #主函數 if __name__ == "__main__": #讀取文本信息 news = read_txt('新聞(中文).txt') print("原文:",news) #清洗數據,去除無關標點 chinese_news = find_chinese(news) print("原文文本:",news) print("純中文文本:",chinese_news) #結巴分詞 chinese_cut = cut_word(chinese_news) print(chinese_cut) # 停用詞去除 chinese_sentence = seg_sentence(chinese_cut) print(chinese_sentence) #詞頻統計 lists = counter(chinese_sentence) print(lists) for list in lists.most_common(20): print(list) #TF-IDF權重計算 tf_idf(chinese_sentence)