文字預處理技術詳解

貪心科技發表於2019-01-16

摘要:自然語言處理NLP(Natural Language Processing),顧名思義,就是使用計算機對語言文字進行處理的相關技術。在對文字做分析時,我們一大半的時間都會花在文字預處理上,而中文和英文的預處理流程稍有不同。本文就對中、英文的常用的文字預處技術做一個總結

文章內容主要按下圖流程講解:

文字預處理技術詳解1.中英文文字預處理的特點

中英文的文字預處理大體流程如上圖,但是還是有一些區別。首先,中文文字沒有像英文用空格來分開不同單詞的,因此不能直接像英文一樣用簡單的空格或標點符號來完成分詞。所以我們一般需要用分詞演算法來完成分詞,具體操作在後面會講到。

當然,英文文字的預處理也有自己特殊的地方比如拼寫問題。很多時候,對英文預處理要包括拼寫檢查,比如“Helo World”這樣的錯誤,我們不能在分析的時候再去糾錯。還有就是詞幹提取(stemming)和詞形還原(lemmatization),主要是因為英文中一個詞會有不同的表達形式,這個步驟有點像孫悟空的火眼金睛,直接得到單詞的原始形態。比如,"faster"、"fastest", 都變為"fast";“leafs”、“leaves”,都變為"leaf"。

2. 收集資料

文字資料的獲取一般有兩種方法:

  • 別人已經做好的資料集,或第三方語料庫如wiki,這樣可以省去很多處理成本。

  • 自己從網上爬取的資料。很多時候我們所面對的是某種特定的領域的應用,這些開放語料庫經常無法滿足我們的需求。我們就需要用爬蟲技術去爬取想要的資訊了。可以使用如beautifulsoup、scrapy等框架編寫出自己需要的爬蟲。

  • 定義資料蒐集策略來蒐集資料可以通過制定資料蒐集策略,從業務的角度來蒐集所需要的資料。 

  • 第三方的合作。通過購買的方式也可以滿足部分資料的需求

3.文字預處理

3.1 去除資料中的非文字部分

由於爬下來的內容中有很多沒必要的標籤比如html的標籤,需要去掉。還有少量的非文字內容也可以直接用Python 的正規表示式(re)刪除, 另外還有一些特殊的非英文字元和標點符號,也可以用Python的正規表示式(re)刪除。

import re

# 過濾不了\\ \ 中文()還有
r1 = u'[a-zA-Z0-9’!"#$%&\'()*+,-./:;<=>?@,。?★、…【】《》?“”‘’![\\]^_`{|}~]+'
#使用者也可以在此進行自定義過濾字元 # 者中規則也過濾不完全
r2 = "[\s+\.\!\/_,$%^*(+\"\']+|[+——!,。?、~@#¥%……&*()]+"
# \\\可以過濾掉反向單槓和雙槓,/可以過濾掉正向單槓和雙槓,第一個中括號裡放的是英文符號,第二個中括號裡放的是中文符號,第二個中括號前不能少|,否則過濾不完全
r3 =  "[.!//_,$&%^*()<>+\"'?@#-|:~{}]+|[——!\\\\,。=?、:“”‘’《》【】¥……()]+" 
# 去掉括號和括號內的所有內容
r4 =  "\\【.*?】+|\\《.*?》+|\\#.*?#+|[.!/_,$&%^*()<>+""'?@|:~{}#]+|[——!\\\,。=?、:“”‘’¥……()《》【】]"

sentence = "hello! wo?rd!."
cleanr = re.compile('<.*?>')
sentence = re.sub(cleanr, ' ', sentence) #去除html標籤
sentence = re.sub(r4,'',sentence)
print(sentence)

3.2 分詞

  • 由於英文單詞間由空格分隔或者其他標點符號分割,所以分詞比較簡單,通常情況下只需要呼叫split()函式即可。

  • 對於中文來說常用的中文分詞軟體有很多,例如,結巴分詞。安裝也很簡單,比如基於Python的,用"pip install jieba"就可以完成。

import jieba 
sentence = "我們學習人工智慧" sentence_seg = jieba.cut(sentence) result = ' '.join(sentence_seg) print(result)

3.3 去掉停用詞

停用詞就是句子中沒必要的單詞,去掉他們對理解整個句子的語義沒有影響。文字中,會存在大量的虛詞、代詞或者沒有特定含義的動詞、名詞,這些詞語對文字分析起不到任何的幫助,我們往往希望能去掉這些“停用詞”。

  • 在英文中,例如,"a","the", “to",“their”等冠詞,藉此,代詞..... 我們可以直接用nltk中提供的英文停用詞表。首先,"pip install nltk"安裝nltk。當你完成這一步時,其實是還不夠的。因為NLTK是由許多的包來構成的,此時執行Python,並輸入下面的指令。

import nltk
from nltk.tokenize import word_tokenize
nltk.download()

然後,Python Launcher會彈出下面這個介面,你可以選擇安裝所有的Packages,以免去日後一而再、再而三的進行安裝,也為你的後續開發提供一個穩定的環境。文字預處理技術詳解

我們可以執行下面的程式碼,看看英文的停用詞庫。

from nltk.corpus import stopwords stop = set(stopwords.words('english')) print(stop)

去除停用詞

sentence = "this is a apple" filter_sentence= [w for w in sentence.split(' ') if w not in stopwords.words('english')] print(filter_sentence)

對於中文停用詞,由於nlkt不支援中文,所以需要自己構造中文停用詞。常用的中文停用詞表是1208個,下載地址在這 。有了中文停用詞表,去除停用詞的程式碼和英文類似,這裡就不贅述了。

3.4 英文單詞--stemming和lemmatization

詞幹提取(stemming)和詞型還原(lemmatization)是英文文字預處理的特色。兩者其實有共同點,即都是要找到詞的原始形式。只不過詞幹提取(stemming)會更加激進一點,它在尋找詞幹的時候可以會得到不是詞的詞幹。比如"leaves"的詞幹可能得到的是"leav", 並不是一個詞。而詞形還原則保守一些,它一般只對能夠還原成一個正確的詞的詞進行處理。nltk中提供了很多方法,wordnet的方式比較好用,不會把單詞過分精簡。

from nltk.stem import SnowballStemmer stemmer = SnowballStemmer("english") # 選擇語言 stemmer.stem("leaves") # 詞幹化單詞
from nltk.stem import WordNetLemmatizer wnl = WordNetLemmatizer() print(wnl.lemmatize('leaves')) 

3.5 英文單詞--轉換為小寫

英文單詞有大小寫之分,Python和python是同一個單詞,所以轉換為小寫可以減少單詞數量。

word = "Python"
word = word.lower() #轉換成lower_case
print(word)

3.6 特徵處理

資料處理到這裡,基本上是乾淨的文字了,現在可以呼叫sklearn來對我們的文字特徵進行處理了。常用的方法如下:

  • Bag of Words詞袋模型

    • Bow

    • Tf-idf

  • N-gram語言模型

    • Bigram

    • Trigram

  • Word2vec分散式模型

    • Word2vec

接下來我將結合程式碼簡單講解一下Tf-idf,Bigram,word2vec的用法。語言模型這一塊內容,可以在之後的文章深入瞭解。

Tf-idf(Term Frequency-Inverse Document Frequency)

該模型基於詞頻,將文字轉換成向量,而不考慮詞序。假設現在有N篇文件,在其中一篇文件D中,詞彙x的TF、IDF、TF-IDF定義如下:

1.Term Frequency(TF(x)):指詞x在當前文字D中的詞頻
2.Inverse Document Frequency(IDF): N代表語料庫中文字的總數,而N(x)代表語料庫中包含詞x的文字總數,平滑後的IDF如下

文字預處理技術詳解

3.TF-IDF : 

使用sklearn庫裡的TfidfVectorizer類可以幫助我們完成向量化,TF-IDF和標準化三步。

from sklearn.feature_extraction.text import TfidfVectorizer 
corpus = ["This is sample document.", "another random document.", "third sample document text"] vector = TfidfVectorizer() tf_data = vector.fit_transform(corpus) print(tf_data)    #(句子下標, 單詞特徵下標)   權重 print(vector.vocabulary_)    #單詞特徵 df1 = pd.DataFrame(tf_data.toarray(), columns=vector.get_feature_names()) # to DataFrame df1

文字預處理技術詳解

N-gram語言模型

詞袋模型不考慮每個單詞的順序。有時候把一句話順序搗亂,我們可能就看不懂這句話在說什麼了,例如:

我玩電腦 = 電腦玩我 ?

N-gram模型是一種語言模型(Language Model),語言模型是一個基於概率的判別模型,它的輸入是一句話(單詞的順序序列),輸出是這句話的概率,即這些單詞的聯合概率(joint probability)。N-gram本身也指一個由N個單片語成的集合,各單詞具有先後順序,且不要求單詞之間互不相同。常用的有 Bi-gram (N=2N=2) 和 Tri-gram (N=3N=3),一般已經夠用了。例如,"I love deep learning",可以分解的 Bi-gram 和 Tri-gram :

Bi-gram : {I, love}, {love, deep}, {love, deep}, {deep, learning}
Tri-gram : {I, love, deep}, {love, deep, learning}

sklearn庫中的CountVectorizer 有一個引數ngram_range,如果賦值為(2,2)則為Bigram,當然使用語言模型會大大增加我們字典的大小。

ram_range=(1,1) 表示 unigram, ngram_range=(2,2) 表示 bigram, ngram_range=(3,3) 表示 thirgram from sklearn.feature_extraction.text import CountVectorizer import pandas as pd import jieba 
data = ["為了祖國,為了勝利,向我開炮!向我開炮!",        "記者:你怎麼會說出那番話",        "我只是覺得,對準我自己打"] data = [" ".join(jieba.lcut(e)) for e in data]         # 分詞,並用" "連線 vector = CountVectorizer(min_df=1, ngram_range=(2,2))  # bigram X = vector.fit_transform(data)                         # 將分詞好的文字轉換為矩陣 print(vector.vocabulary_ )                             # 得到特徵 print(X)                                               #(句子下標, 單詞特徵下標)   頻數 df1 = pd.DataFrame(X.toarray(), columns=vector.get_feature_names()) # to DataFrame df1.head()

文字預處理技術詳解

Word2vec詞向量

Word2Vec使用一系列的文件的詞語去訓練模型,把文章的詞對映到一個固定長度的連續向量。一般維數較小,通常為100 ~ 500。意義相近的詞之間的向量距離較小。它以稠密的向量形式表示單詞。有兩種模式:

CBOW(Continuous Bag-Of-Words):利用詞的上下文預測當前的詞。
Skip-Gram:利用當前的詞來預測上下文。

因為word2vector模型的得到的是詞向量,如何表示句子呢?最簡單的方法就是,將每個句子中的詞向量相加取平均值,即每個句子的平均詞向量來表示句子的向量。

from gensim.models import Word2Vec                   import numpy as np 
data = ["I love deep learning","I love studying","I want to travel"] #詞頻少於min_count次數的單詞會被丟棄掉 #size指特徵向量的維度為50 #workers引數控制訓練的並行數 train_w2v = Word2Vec(data,min_count=5,size=50, workers=4) for row in data:         #計算平均詞向量,表示句子向量    vec = np.zeros(50)    count = 0    for word in row:        try:            vec += train_w2v[word]            count += 1        except:            pass    avg_data.append(vec/count)   print(avg_data[1])
文字預處理技術詳解

4. 建立分析模型

有了每段文字的特徵向量後,我們就可以利用這些資料建立分類模型,或者聚類模型了,或者進行相似度的分析。

5.總結

3.6小節中的特徵提取一塊,為了demo演示的方便,沒有和前面的分詞,清洗,標準化結合在一起。如果是從分詞步驟開始做的文字預處理,需要注意:在特徵提取時,要將每個句子的單詞以空格連線起來。

參考:

1.  貪心學院NLP課程,http://www.greedyai.com/course/47/summary/introduceNlp

2. Text preprocessing using python,https://www.kaggle.com/shashanksai/text-preprocessing-using-python

3. Pre-processing-in-natural-language-machine-learninghttp://link.zhihu.com/?target=https%3A//towardsdatascience.com/pre-processing-in-natural-language-machine-learning-898a84b8bd47

4. NLP中的語言模型及文字特徵提取演算法,

https://blog.csdn.net/tiffanyrabbit/article/details/72650606

5. https://blog.csdn.net/ximibbb/article/details/79264574

知乎原文連結:https://zhuanlan.zhihu.com/p/53277723

相關文章