【譯文】基於Python的自然語言處理指南

作者 Shivam Bansal

譯者 錢亦欣

根據業界估計,僅有約21%的數據是以結構化的形式出現的。現在,我們所說的話,發的微博,發送到各個APP上的信息都是重要的數據來源。這部分數據大部分以文本的形式存在,天生的非結構化。

拋開維度不談,從這些據道採集的數據在手工加工或者用自動化的系統解析之前是沒法直接建模分析的。

為了從文本數據得到顯著而有用的信息,學習一些自然語言處理(NLP)方法尤為重要。

如果你今年計劃編寫一個聊天機器人,或者想要掌握文本預處理技術,本文是個不錯的入門。本文將闡述NLP的基本原理、技術和應用方法。本文的目標就是讓你能針對真實數據集應用這些方法。

目錄

  1. NLP簡介

  2. 文本預處理

    • 去除雜訊

    • 辭彙規範化

      • 詞幹提取

      • 詞形還原

    • 對象標準化

  3. 文本特徵化 (文本數據的特徵工程)

    • 句法分析

      • 從屬關係語法

      • 詞性標註

    • 實例分析

      • 短語檢測

      • 命名實體識別

      • 主題建模

      • N元文法模型 (N-Grams)

    • 統計特徵

      • TF – IDF

      • 頻率/密度特徵

      • 可讀性特徵

    • 單詞嵌入

  4. NLP重要任務

    • 文本分類

    • 文本匹配

      • 編輯距離

      • 語音匹配

      • 柔性字元串匹配

    • 指代消解

    • 其他

  5. 重要的NLP庫

1. NLP簡介

NLP是數據科學的一大分支,旨在以智能而高效的方法來分析文本數據中潛藏的信息。採用適當的技術,你可以實現諸如自動總結,機器翻譯,命名實體識別,情感分析等任務。

在進一步深入之前,讓我先來解釋下文會出現的一些術語:

  • 標記化 – 把文本轉化為標記的過程

  • 標記 – 文本中出現的實體或辭彙

  • 文本對象 – 詞語、片語、句子、文章

安裝NLTK庫和其數據集:

安裝pip: 在終端中運行:

sudo easy_install pipn

安裝NLTK: 在終端中運行:

sudo pip install -U nltkn

下載NLTK數據: 在python中運行如下代碼:

import nltk nnltk.download()n

按照屏幕上出現的指示,下載需要的包或者集合,其他庫庫可以通過pip下載

2. 文本預處理

由於文本是一種高度非結構化的數據,其中會蘊含這各種類型的噪音,如果不做預處理是無法分析的。將文本清洗並標準化,使得其噪音含量低可進行分析的全過程稱為文本預處理。

上述過程一般包括如下步驟:

  • 去除雜訊

  • 辭彙規範化

  • 對象標準化

下圖展示來文本預處理工作流程

2.1 去除雜訊

任何與文本數據內容不相關或是與最終輸出無關的文本塊被視作雜訊。

舉個例子,語言中的定冠詞,一些介詞,網頁地址,社交媒體實例(標籤等)和一些特有名詞都是雜訊。這個步驟目標就是把所有類型的雜訊都移除。

去除雜訊的通用最發是準備一個雜訊實體的字典,然後把文本對象中的標記(或者詞)逐個對照,如果它被包含在字典里,就移除。

下列python代碼就實現來這個過程

# 移除文本雜訊的示範代碼nnoise_list = ["is", "a", "this", "..."]ndef _remove_noise(input_text):n words = input_text.split()n noise_free_words = [word for word in words if word not inn noise_list]n noise_free_text = " ".join(noise_free_words)n return noise_free_text_remove_noise("this is a sample text")n>>> "sample text"n

另一種方法是利用正則表達式來處理有特殊模式的雜訊。我在先前的文章中已經介紹過相關細節,按照下列代碼就嗯能移除輸入文本中特定模式的雜訊。

# 移除固定模式雜訊的示例代碼nimport re ndef _remove_regex(input_text, regex_pattern):n urls = re.finditer(regex_pattern, input_text)n for i in urls:n input_text = re.sub(i.group().strip(), , input_text)n return input_textnregex_pattern = "#[w]*"n n_remove_regex("remove this #hashtag from analytics vidhya", regex_pattern)n>>> "remove this from analytics vidhya"n

2.2 辭彙規範化

另一種文本雜訊的形式是由多個單詞形成的表達式

舉個例子 - "play", "player", "played", "plays", "playing"同一個單詞的不同時態或者詞性變化,儘管形式不同但意義上相近。這步會把所有這一類的辭彙規範化為同一範式(a.k.a. lemma)。規範化是文本數據特徵工程的主要步驟,它把高維特徵(N個不同特徵)映射到來低維空間(1個特徵),這對很多機器學習模型而言都是理想情況。

最常用的辭彙規範化技術是:

  • 詞幹提取: 詞幹提取是基於一些基本規則將辭彙的後綴("ing", "ly", "es", "s"等)剝離的過程

  • 詞形還原: 詞形還原是一種逐步還原詞根的過程, 它基於辭彙和詞法分析實現這個目的。

下列是利用python中的NLTK庫實現詞法分析和詞幹提取的示例代碼

from nltk.stem.wordnet import WordNetLemmatizernlem = WordNetLemmatizer()nnfrom nltk.stem.porter import PorterStemmernstem = PorterStemmer()nnword = "multiplying"nlem.lemmatize(word, "v")n>> "multiply"nstem.stem(word)n>> "multipli"n

2.3 對象標準化

文本數據中時常有些詞或者短語無法在標準詞典里找到,這些內容不會被搜索引擎或者模型識別。

例子包括:一些縮寫詞,包含詞語的標籤和俚語辭彙。好在利用正則表達式和手工收集的詞典可以解決這一問題。下倆代碼就能將社交媒體俚語進行替換。

lookup_dict = {rt:Retweet, dm:direct message, "awsm" : "awesome", "luv" :"love", "..."}ndef _lookup_words(input_text):n words = input_text.split()n new_words = []n for word in words:n if word.lower() in lookup_dict:n word = lookup_dict[word.lower()]n new_words.append(word)n new_text = " ".join(new_words)n return new_textnn_lookup_words("RT this is a retweeted tweet by Shivam Bansal")n>> "Retweet this is a retweeted tweet by Shivam Bansal"n

除了本文介紹的三種方法,其他的文本預處理內容發包括編碼-解碼雜訊,語法檢測和拼寫糾正。相關細節可以看我以前寫的這篇文章。

3.文本特徵化 (文本數據的特徵工程)

為了分析預處理後的數據,我們需要將其轉化為特徵。基於不同的用途,文本特徵可以利用配套技術-句法分析,基於實體/N元文法/單詞的特徵,統計特徵和單詞嵌入。下文會詳細闡述這些技術。

3.1 句法分析

句法分析包括對句中單詞在語法和排列方式(與其他單詞的相關關係)兩方面的分析。從屬關係語法和語音標籤是句法分析的重要屬性。

從屬關係樹(Dependency Trees) – 句子是單詞的集合,句子中單詞的相互關係依賴於基本的從屬關係語法。從屬關係語法專門處理(帶標籤的)兩個辭彙單元(單詞)的非對稱二元關係。每種關係都可以用三元表示法(relation, governor, dependent)關係顯示 舉個例子:考慮如下句子「Bills on ports and immigration were submitted by Senator Brownback, Republican of Kansas.」 該句單詞的關係可以用如下的樹狀結構表示:

該樹狀結構表示單詞「submitted」是這句話的根單詞(root word),並且其與兩棵子樹相連(主題和客體子樹)。 每顆子樹又有自己的從屬關係樹結構,比如 – (「Bills」 <-> 「ports」 <by> 「proposition」 relation), (「ports」 <-> 「immigration」 <by> 「conjugation」 relation)。

當我們通過自上而下的迭代方法梳理好單詞的從屬關係後,就可以基於此將其作為特徵解決NLP領域的很多問題了,比如情感分析、實體識別和文本分類等。Python的包裝器StanfordCoreNLP(由斯坦福NLP小組提供,僅供商業使用)和NLTK庫中的相關語法可以用來生成從屬關係樹。

詞性標註 – 除了語法關係,句中單詞的位置(詞性)標記也蘊含著信息,詞的位置定義了它的用途和功能。賓夕法尼亞大學提供了一個完整的位置標記列表。下方代碼則使用了NLTK庫來對輸入的文本進行詞性標註。

from nltk import word_tokenize, pos_tagntext = "I am learning Natural Language Processing on Analytics Vidhya"ntokens = word_tokenize(text)nprint pos_tag(tokens)n>>> [(I, PRP), (am, VBP), (learning, VBG), (Natural, nNNP),(Language, NNP),(Processing, NNP), (on, IN), n(Analytics, NNP),(Vidhya, NNP)]n

在NLP中,詞性標註有個很多重要用途:

A.消除歧義: 一些詞的不同用法代表不同的意思. 如下列兩句:

I. 「Please book my flight for Delhi」

II. 「I am going to read this book in the flight」

「Book」 在這裡代表不同的意義, 好在它在兩句的位置也不同. 第一句「book」是的動詞, 第二句中它是個名詞。 (Lesk Algorithm也被用於類似目的)

B.強化基於單詞的特徵: 一個機器學習模型可以從一個詞的很多方面提取信息,但如果一個詞已經標註了詞性,那麼它作為特徵就能提供更精準的信息。 例如:

句子 -「book my flight, I will read this book」

單詞 – (「book」, 2), (「my」, 1), (「flight」, 1), (「I」, 1), (「will」, 1), (「read」, 1), (「this」, 1)

帶標註的單詞 – (「book_VB」, 1), (「my_PRP$」, 1), (「flight_NN」, 1), (「I_PRP」, 1), (「will_MD」, 1), (「read_VB」, 1), (「this_DT」, 1), (「book_NN」, 1)

譯者註:如果不帶詞性標註,兩個「book」就被認為是同義詞,詞頻為2。這會在後續分析中引入誤差。

C.標準化與詞形還原: 位置標註是詞形還原的基礎步驟之一,可以幫助把單詞還原為基本形式.

D.有效移除停用詞 : 利用位置標記可以有效地去除停用詞。

舉個例子,有一些標註可以知名某些語言中的低頻詞和不重要的詞,像方位介詞,數量詞和語氣助詞等。

3.2 實體提取(實體作為特徵)

實體指名詞短語或者動詞短語,被認為是句子最重要的組成部分。實體檢測演算法則是基於解析規則,詞典搜索,位置標註和從屬關係分析的一類模型的集合。實體檢測演算法可被應用於自動聊天機器人,內容分析和消費者行為分析等。

主題模型和命名實體識別是NLP中實體檢測的兩大主流方法。

A. 命名實體識別(NER)

檢測諸如人名、地名和公司名之類的命名實體的過程被稱為NER,比如:

句子 – Sergey Brin, the manager of Google Inc. is walking in the streets of New York.

命名實體 – ( 「person」 : 「Sergey Brin」 ), (「org」 : 「Google Inc.」), (「location」 : 「New York」)

一個典型的NER模型包括三個模塊:

名詞短語識別 該步驟會根據從屬關係分析和詞性標註提取文本中所有的名詞短語

短語分類 該步驟把提取出的名詞短語分到相應的類別(位置,姓名等)。Google地圖的API提供了很好的位置歸類方法,而利用dbpedia和wikipedia的資料庫可以用來識別公司名和人名。如此之外,也可以認為把多渠道收集的數據整合為字典用於分類。

實體消除歧義 有時一個實體會被錯誤地分類,所以我們需要對分類結果加一層檢驗。使用知識圖譜可以實現這一目的,使用較多的知識圖譜包括Google知識圖譜,IBM Watson和Wikipedia。

B. 主題模型

主題建模是識別文本所屬主題的過程,它會以非監督技術識別單詞間的潛在技術。主題被定義為語料庫中以片語形式重複出現的模式。一個好的主題模型會把健康方面的文本主題總結為「health」,「doctor」,「patient」,「hospital」,把農耕方便的主題總結為「farm」,「crops」,「wheat」。

潛在狄利克雷分配模型(LDA)是最流行的主題建模技術,下列代碼是在Python中建立LDA模型的過程。如果需要LDA模型的詳細解釋和技術細節,可以參考這篇文章

doc1 = "Sugar is bad to consume. My sister likes to have sugar, but not my father."ndoc2 = "My father spends a lot of time driving my sister around to dance practice."ndoc3 = "Doctors suggest that driving may cause increased stress and blood pressure."ndoc_complete = [doc1, doc2, doc3]ndoc_clean = [doc.split() for doc in doc_complete]nnimport gensim from gensimnimport corporann# 建立一個語料庫詞典,其中每個片語都進行了編號ndictionary = corpora.Dictionary(doc_clean)nn# 使用前一部構建的詞典,把語料庫詞典從列錶轉換為文獻-檢索詞矩陣n(DTM)doc_term_matrix = [dictionary.doc2bow(doc) for doc in doc_clean]nn# 使用gensim庫構建LDA模型nLda = gensim.models.ldamodel.LdaModelnn# 使用DTM構建並訓練LDA模型nldamodel = Lda(doc_term_matrix, num_topics=3, id2word = dictionary, npasses=50)nn# 結果nprint(ldamodel.print_topics())n

C. 把N元文法作為特徵

N個單詞構成的組合稱為N元文法。N元文法(N > 1)通常比單詞(一元文法)包含更多信息。此外,兩元文法被認為是最重要的特徵,下列代碼能從文本中生成二元文法。

def generate_ngrams(text, n):n words = text.split()n output = []n for i in range(len(words)-n+1):n output.append(words[i:i+n])n return outputn>>> generate_ngrams(this is a sample text, 2)n# [[this, is], [is, a], [a, sample], , [sample, text]] n

3.3 統計特徵

文本數據也可以借用一些技術量化:

A. 片語頻率-逆文檔頻率 (TF – IDF)

TF-IDF是信息檢索領域的常用模型。它的工作原理是基於單詞在文檔中頻率(不考慮序關係)把文本文檔轉化為向量的形式。舉個例子,假設有一個由N個文本文檔組成的數據集,在任一文檔「D」中,TF和IDF被定義為:

片語頻率(TF) – 片語「t」的TF被定義為其在文檔「D」中的出現次數

逆文檔頻率(IDF) – 片語的IDF被定義為其數據集中文檔總數和包含該片語文檔樹的比值的自然對數。

TF - IDF - TF-IDF 公式給出了片語在語料庫(文檔列表)中的相對重要性的度量,公式如下:

下方代碼使用python中的scikit-learn庫來把文本轉化為TF-IDF向量:

from sklearn.feature_extraction.text import TfidfVectorizernobj = TfidfVectorizer()ncorpus = [This is sample document., another random document., third sample document text]nX = obj.fit_transform(corpus)nprint Xn>>>n(0, 1) 0.345205016865n(0, 4) ... 0.444514311537n(2, 1) 0.345205016865n(2, 4) 0.444514311537n

該模型會建立一個辭彙字典,再給每個單詞分配一個編號。輸出中的每一行包括一個元組(i,j)和文檔i中標號為j的片語的TF-IDF值。

B. 頻率 / 密度 / 可讀性特徵

基於頻率或者密度的特徵也被廣泛用於建模和分析,這類特徵可能看起來很簡單卻往往能發揮很大的作用。這類特徵有:詞頻,句頻,標點頻率和行業術語頻率。而另一類包括音節頻率,SMOG指數和易讀性指標的可讀性特徵,請參看Textstat庫的相關內容。

3.4 單詞嵌入 (文本向量)

單詞嵌入是把詞語向量化的現代方法,其目標是通過語料庫的情景相似性把高維單詞特徵重新定義為低維向量。它們在深度學習(如卷積神經網路和循環神經網路)中被廣泛使用。 Word2Vec 和 GloVe 是單詞嵌入的常用庫,這些模型把文本語料庫作為輸入,並把文本向量作為輸出。

Word2Vec模型是預處理模型和一兩種分別叫做連續詞包和skip-gram淺層神經網路的集合體。這些模型在NLP的其他領域也持續發光發熱。它首先通過訓練預料庫形成一個辭彙表,然後再學習單詞嵌入表達式。下列代碼使用gensim庫把單詞嵌入到向量里:

from gensim.models import Word2Vecnsentences = [[data, science], [vidhya, science, data, analytics],[machine, learning], [deep, learning]]nn# 使用語料庫訓練模型nmodel = Word2Vec(sentences, min_count = 1)nnprint model.similarity(data, science)n>>> 0.11222489293nnprint model[learning]n>>> array([ 0.00459356 0.00303564 -0.00467622 0.00209638, ...])n

它們可以作為機器學習模型的向量化輸入,可以利用餘弦定理來衡量文本相似性,還可以做詞雲和被用於文本分類。

4. NLP的重要任務

本部分會討論NLP領域的不同應用場景和常見問題。

4.1 文本分類

文本分類是NLP的典型問題之一,具體的例子包括但不僅限於 - 垃圾郵件識別,新聞主題分類,情感分析和搜索引擎的網頁排序。

文本分類通俗地說將文本對象(文檔或句子)按照一定規律分配到某一固定類別中的過程。當數據總量很大時,從組織,信息過濾和存儲方面考慮,分類就顯得尤為重要。

一個典型的NLP分類器包含兩部分:(a)訓練 (b)預測。如下圖所示,輸入的文本會先經過預處理過程再被提取特徵,之後相應的機器學習模型就會接受特徵並對新文本作出類別預測。

這裡的代碼就使用了樸素貝葉斯分類器(包含在blob庫中)來實現文本分類過程:

from textblob.classifiers import NaiveBayesClassifier as NBCnfrom textblob import TextBlobntraining_corpus = [n (I am exhausted of this work., Class_B),n ("I cant cooperate with this", Class_B),n (He is my badest enemy!, Class_B),n (My management is poor., Class_B),n (I love this burger., Class_A),n (This is an brilliant place!, Class_A),n (I feel very good about these dates., Class_A),n (This is my best work., Class_A),n ("What an awesome view", Class_A),n (I do not like this dish, Class_B)]nntest_corpus = [n ("I am not feeling well today.", Class_B),n ("I feel brilliant!", Class_A),n (Gary is a friend of mine., Class_A),n ("I cant believe Im doing this.", Class_B),n (The date was good., Class_A),n (I do not enjoy my job, Class_B)]nnmodel = NBC(training_corpus)nprint(model.classify("Their codes are amazing."))n>>> "Class_A"nprint(model.classify("I dont like their computer."))n>>> "Class_B"nprint(model.accuracy(test_corpus))n>>> 0.83n

Scikit.Learn也提供了文本分類的工作流程:

from sklearn.feature_extraction.text import TfidfVectorizer nfrom sklearn.metrics import classification_reportnfrom sklearn import svm n# 為SVM準備數據 (和樸素貝葉斯分類器使用同樣特徵)ntrain_data = []ntrain_labels = []nfor row in training_corpus:n train_data.append(row[0])n train_labels.append(row[1])nntest_data = []ntest_labels = []nfor row in test_corpus:n test_data.append(row[0])n test_labels.append(row[1])nn# 創建特徵向量nvectorizer = TfidfVectorizer(min_df=4, max_df=0.9)n# 訓練特徵向量ntrain_vectors = vectorizer.fit_transform(train_data)n# 在測試集上應用模型 ntest_vectors = vectorizer.transform(test_data)nn# 訓練使用線性核的SVM模型nmodel = svm.SVC(kernel=linear)nmodel.fit(train_vectors, train_labels)nprediction = model.predict(test_vectors)n>>> [Class_A Class_A Class_B Class_B Class_A Class_A]nnprint (classification_report(test_labels, prediction))n

文本分類器的效果和特徵的質量與數量關係很大,使用任一機器學習模型輸入更多的訓練數據總是更好的。

4.2 文本匹配/相似度

NLP的另一重要領域是匹配文本對象來計算相似度。它可以應用在拼寫糾正,數據去重和基因組分析等。

依據不同的需求,現在已有很多中匹配技術可供使用,這部分會詳細介紹常用的幾種。

A. Levenshtein 距離 – 兩個字元串間的Levenshtein距離被定義為將一個字元串轉化為另一字元串所需要變動的修正數的最小值。其中,修正指單個字元的插入、刪除或替換。下列代碼能使用一種很省內存的演算法計算該距離.

def levenshtein(s1,s2):n if len(s1) > len(s2):n s1,s2 = s2,s1n distances = range(len(s1) + 1)n for index2,char2 in enumerate(s2):n newDistances = [index2+1]n for index1,char1 in enumerate(s1):n if char1 == char2:n newDistances.append(distances[index1])n else:n newDistances.append(1 + min((distances[index1], distances[index1+1], newDistances[-1])))n distances = newDistancesn return distances[-1]nnprint(levenshtein("analyze","analyse"))n

B. 語音匹配 – 語音匹配演算法會把關鍵詞(人名、地名等)作為輸入,之後返回一個能大致代表輸入類別的單詞。在對大型語料庫進行索引,糾正拼寫錯誤和匹配相關姓名時很有作用。Soundex和Metaphone是這一領域的兩大主要演算法,Python中的Fuzzy庫能實現Soundex演算法,比如:

import fuzzy nsoundex = fuzzy.Soundex(4) nprint soundex(ankit)n>>> 「A523」nprint soundex(aunkit)n>>> 「A523」 n

C. 柔性字元串匹配 – 一套完整的文本匹配系統會包含各種不同的演算法以適應文本的多樣性。正則表達式對此也能發揮很大的作用。而另一種常用技術則包括 - 精確字元串匹配,詞形還原匹配和緊湊匹配等。

D. 餘弦相似度 – 當文本以向量形式出現時,使用餘弦定理就能衡量兩個文本的相似度了。下列代碼就把文本按照詞頻轉換成向量並使用餘弦值來衡量兩個文本的相似度。

import mathnfrom collections import Counterndef get_cosine(vec1, vec2):n common = set(vec1.keys()) & set(vec2.keys())n numerator = sum([vec1[x] * vec2[x] for x in common])nn sum1 = sum([vec1[x]**2 for x in vec1.keys()])n sum2 = sum([vec2[x]**2 for x in vec2.keys()])n denominator = math.sqrt(sum1) * math.sqrt(sum2)n n if not denominator:n return 0.0n else:n return float(numerator) / denominatornndef text_to_vector(text):n words = text.split()n return Counter(words)nntext1 = This is an article on analytics vidhyantext2 = article on analytics vidhya is about natural language processingnnvector1 = text_to_vector(text1)nvector2 = text_to_vector(text2)ncosine = get_cosine(vector1, vector2)n>>> 0.62n

4.3 指代消解

指代消解可以尋找句內單詞(或短語)間的相關關係。考慮如下例子:「 Donald went to John』s office to see the new table. He looked at it for an hour.」人類可以識別句中的「he」指代Donald而非John,「it」指代table而非office。NLP中的指代消解則可以自動實現這一過程。它被應用於文檔總結,自動答題和信息提取等方面,斯坦福的CoreNLP項目提供了Python封裝供商業使用。

4.4 其他問題 / 任務

  • 文本總結 – 給定文檔或者段落,識別出其中的關鍵句。

  • 機器翻譯 – 自動翻譯輸入的人類語言,對語法、語義和信息保真度較高。

  • 自然語言的生成和理解 – 把計算機資料庫中的信息轉化為可讀的人類語言稱為語言生成。而把文本塊轉化成計算機更容易處理的邏輯結構的過程稱為語言理解。

  • 光學字元識別(OCR) – 給定圖片,識別其中文字。

  • 文檔信息化 – 把文本數據(網頁,文件,pdf和圖像)中的信息轉化為可信息的乾淨格式。

5. 重要的NLP庫(python)

  • Scikit-learn: 機器學習庫

  • Natural Language Toolkit (NLTK): 為各種NLP技術提供輪子

  • Pattern – 網頁挖掘模塊,和NLTK搭配使用

  • TextBlob – 方便的NLP工具的API,基於NLTK和Pattern架構

  • spaCy – 工業級的NLP庫

  • Gensim – 可構建主題模型

  • Stanford Core NLP – 斯坦福NLP小組提供的各類服務

結語

希望本文能幫祝你快速殺入Python界的NLP領域,有任何建議和意見請留言

譯者註:本文對自然語言處理也是一竅不通,希望通過本文掌握基本概念。如果本文的術語有翻譯錯誤或者不到位的地方請在下方留言。新年降至,專欄暫時停更。祝各位雞年大吉吧!

註:原文刊載於Analytics Vidhya網站

原文鏈接Ultimate Guide to Understand & Implement Natural Language Processing (with codes in Python)

推薦閱讀:

TAG:Python | 自然语言处理 | 文本分析 |