機器學習 | 八大步驟解決90%的NLP問題

機器學習 | 八大步驟解決90%的NLP問題

來自專欄 從零學AI

本文將分八大步驟來介紹如何用機器學習處理文本數據。從最簡單的方法開始,逐一講解,然後分析更具體的方案細節,如特徵工程、詞向量和深度學習。你可以把本文看作是標準方法的高度概括。

代碼鏈接:

github.com/hundredblock

一、收集數據

每一個機器學習問題都始於數據,比如一組郵件、帖子或是推文。文本信息的常見來源包括:

  • 商品評價(來自 Amazon、Yelp 以及其他 App 商城)
  • 用戶產出的內容(推文、Facebook 的帖子、StackOverflow 的提問等)
  • 問題解決(客戶請求、技術支持、聊天記錄)

「社交媒體中的災難」數據集

在這篇文章中,我們將使用 CrowdFlower 提供的一個數據集,名為「社交媒體中的災難(Disasters on Social Media)」。

貢獻者們查看了超過 10000 條具有類似「著火」、「隔離」、「混亂」等搜索關鍵詞的推文,然後標記這個推文是否和災難事件有關(與之相反的是一些玩笑、電影點評或是一些非災難性的事件)。

我們的任務是分辨出哪些推文是真正和災難事件相關的,而不是一些類似電影描述的不相關話題。為什麼呢?一個潛在的應用是針對突發事件對執法人員進行專門的提醒,而不會被其他無關信息,比如 Adam Sandler 新上映的電影所干擾。這項任務中一個特別的挑戰是這兩種情況在搜索推文的時候都用到了相同的檢索詞,所以我們只能通過細微的差別去區分他們。

在下面的文章中,我們將把與災難事件相關的推文稱為「災難」,將其他推文稱為「不相關的」。

標籤

我們已經標註過數據,所以知道推文是如何分類的。比起優化一個複雜的無監督學習方法,尋找和標記足夠多的數據來訓練模型會更加快捷、簡單和廉價。

二、數據清洗

數據科學家的一個必備技能是知道自己的下一步操作是處理模型還是數據。有一個好的經驗法則是先觀察數據然後進行數據清洗。一個乾淨的數據集能使模型學習到有意義的特徵而不會被一些不相關的雜訊影響。

可以借鑒下方的列表來進行數據清洗:(查看代碼獲取更多信息)

  • 去除一切不相關的字元,比如任何非字母數字的字元
  • 標記你的文本,將他們拆分為獨立的單詞
  • 去除不相關的詞語,比如 @這類提醒或是 url 鏈接
  • 將所有字母轉換成小寫,這樣「hello」,「Hello」,「HELLO」就會被當做同樣的單詞處理
  • 將拼錯的單詞或是多種拼法的單詞與某個特定的表達綁定(比如:「cool」/「kewl」/「cooool」)
  • 考慮詞形還原(比如將「am」,「are」,「is」都看做「be」)

完成這些步驟並檢查完其他錯誤後,我們就可以使用這些乾淨的、標記過的數據進行模型訓練了!

代碼:github.com/hundredblock

三、找到一種好的數據表達方式

機器學習模型通常以數值作為輸入。我們這裡的數據集是句子列表,為了讓模型可以從數據中學到句子的特徵模式,我們首先要找到一種方法來把它轉換成模型能理解的形式,即數字列表。

獨熱編碼(One-hot encoding)- 詞袋模型(Bag of Words)

通常為計算機解釋文本的方法是將每一個字元都編為一個獨立的數字(例如 ASCII 碼)。如果使用這種簡單的表達來做分類器,需要我們的數據從頭開始學習詞語的結構,這對大多數數據集來說是很難實現的。所以我們需要一種更上層的方法。

例如,我們可以為數據集中的所有單詞製作一張詞表,然後將每個單詞和一個唯一的索引關聯。每個句子都是由一串數字組成,這串數字是詞表中的獨立單詞對應的個數。通過列表中的索引,我們可以統計出句子中某個單詞出現的次數。這種方法叫做 詞袋模型,它完全忽略了句子中單詞的順序。如下圖所示:

用詞袋模型表示句子。句子在左邊,模型表達在右邊。向量中的每一個索引代表了一個特定的單詞。

嵌入可視化

在「社交媒體中的災難」樣本詞表中大概會有 20000 個單詞,這意味著每句句子都會用一個長度為 20000 的向量來表示。向量的 大部分會被 0 填充,因為每句話只包含了詞表中很小的一個子集。

為了看出嵌入的工作是否真正抓住了和問題相關的信息(比如推文是否與災難相關),有一個好方法是將它們可視化,然後觀察結果是否有很好的分布。考慮到詞表通常很大,而且用 20000 維的數據做可視化是基本不可能的,所以我們使用了 PCA 這種技術將數據降到二維。繪製如下:

詞袋嵌入模型的可視化結果

兩個分類看起來沒有很好的分離,這可能是我們選擇的嵌入方法的特徵或是單純因為維度的減少引起的。為了了解詞袋模型的特徵是否會起一些作用,我們可以試著基於它訓練一個分類器。

四、分類

當初次接觸一個問題,通常來說最好的方法是先挑選一個能解決問題的最簡單的工具。當提到數據分類時,一般最受歡迎的是通用性和可解釋性兼具的邏輯回歸演算法。這種演算法很容易訓練而且結果也是可解釋的,你可以很輕鬆地從模型中提取出最重要的一些係數。

我們將數據分為兩個集合,訓練集用於匹配模型,測試集用於觀察應用在未知數據上的效果。訓練後我們得到了 75.4% 的精確度。結果還不錯!推測出現最多的類(「不相關」)只能達到 57%。但是,即使是 75% 的精確度也已經足夠好了,我們決不能在還沒有理解模型的情況下就開始應用它。

五、檢驗混淆矩陣

理解模型的第一步,是了解模型產生的錯誤分類,以及最不應該出現的錯誤。在我們的例子中,「誤報」是指將不相關的推文分類為「災難事件」,「漏報」是指將與災難有關的推文歸類為「與災難無關的事件」。如果要優先處理潛在的災難事件,那就要降低「漏報」。而如果資源受限,就要優先降低「誤報」,減少錯誤的提醒。使用混淆矩陣可以很好地可視化這些信息,並將模型預測的結果與數據的真是標籤進行比較。理想情況下,模型的預測結果與真實情況(人工標註)完全相符,這時候混淆矩陣是一條從左上角到右下角的對角矩陣。

混淆矩陣(綠色部分所佔比例較高,藍色部分的比例較低)

相比假陽性結果,我們的分類器產生了更多的假陰性結果。換句話說,模型中最常見的錯誤是將災難性推文錯誤歸類為不相關推文。如果假陽性結果的執法成本很高的話,那麼我們分類器的這種偏差就是良性的。

解釋和說明模型

為了驗證模型並解釋它的預測結果,我們需要明確模型用以進行判斷的那些辭彙。如果我們的數據有偏差,而分類器在樣本數據中卻能做出準確預測,那這樣的模型就無法在現實世界中很好地推廣。

在這裡,我們可以用圖表來表示災難性推文與不相關推文兩類預測中最重要的辭彙。由於我們可以對模型的預測係數進行提取和排序,用詞袋模型(bag-of-words)和Logistic回歸模型很容易就能計算出單詞的重要性。

詞袋模型(bag-of-words):單詞的重要性

我們的分類器能夠正確識別出一些模式(如廣島、大屠殺等),但在一些毫無意義的辭彙(如heyoo、x1392等)上還是出現了過擬合。詞袋模型(bag-of-words)僅能處理龐大辭彙表內的不同辭彙,並對所有的辭彙分配相同的權重。然而,其中一些辭彙出現得非常頻繁,但卻只是預測結果的噪音數據。接下來,我們將試著找到一種能夠表示辭彙在句子中出現頻率的方法,盡量讓模型從數據中獲取更多的信號。

六、辭彙結構的統計

TF-IDF嵌入模型

為了讓模型專註於學習更有意義的辭彙,我們可以在詞袋模型上面使用TF-IDF評分(術語頻率,逆文檔頻率)。TF-IDF通過辭彙在數據集中的稀有程度來評估它的重要性,適度削弱出現過於頻繁的單詞。下圖是TF-IDF嵌入模型的PCA映射:

可視化TF-IDF嵌入模型

從中可以看出,兩種顏色之間有了更清晰的區分,使這兩類數據更易於被分類器分開。在新模型上訓練Logistic回歸,我們得到了76.2%的準確度,說明TF-IDF確實有助於提高識別性能。

儘管只是非常微小的改進,但我們的模型能否就此學到更重要的辭彙呢?如果能得到更好的結果,同時還能避免模型在無關辭彙上的過擬合,那TF-IDF嵌入模型就可以被認為是真正的「升級版」模型。

TF-IDF嵌入模型:單詞的重要性

可以看到,新模型學到的辭彙看起來相關度更高!儘管測試集的指標只是略有增加,但是我們對模型的識別性能更有把握,因此部署新模型的交互系統會讓用戶體驗更為舒適。

七、語義信息的利用Word2Vec

TF-IDF嵌入模型能夠學習到信號更高頻的辭彙。然而,如果部署該模型後,我們很可能會遇到一些訓練集中從未出現過的辭彙。先前的模型均無法正確分類這樣的新數據,即便其中的辭彙與訓練集非常相似。

要解決這個問題,我們就要捕捉辭彙的語義,這就意味著模型需要理解「好」與「積極」在語義上的距離要比「杏」和「大陸」更接近。這裡的工具就是Word2Vec。

使用預訓練的嵌入模型

Word2Vec是一種為單詞查找連續嵌入的技術。通過閱讀大量的文字,它能夠學習並記憶那些傾向於在相似語境中出現的辭彙。經過足夠的數據訓練之後,它會為辭彙表中的每個單詞都生成一個300維的向量,用以記錄語義相近的辭彙。

Word2Vec作者在一個非常大的語料庫上預訓練並開源了該模型。利用這一語料庫,我們可以將一些語義知識納入到我們的模型內。預訓練好的詞向量可以在本文的GitHub代碼庫中找到。

GitHub地址:github.com/hundredblock

句子分級表示

讓分類器快速得到句子嵌入的方法,是先將句中所有辭彙Word2Vec得分的平均化。這與此前詞袋模型的做法類似,但這裡我們在保留語義信息的同時只丟棄句法。

Word2vec模型的句子嵌入

利用前面的可視化技術對新模型繪圖,結果如下:

Word2Vc嵌入模型的可視化結果

在這裡,兩組顏色的分離程度更大一些,這就意味著Word2Vec能夠幫助分類器更好地分離這兩種類別。再一次使用Logistic回歸,得到77.7%的準確率,是我們迄今最好的結果!

複雜性/可解釋性權衡取捨

與先前的模型不同,新模型無法將每個單詞都表示成一維向量,因此很難看出哪些辭彙與我們的分類結果相關度最高。儘管我們仍可使用Logistic回歸的係數,但它們僅與嵌入的300個維度相關,而與辭彙索引值並不相關。

模型準確率確實提高了,但完全做不了可解釋性分析就有點得不償失了。不過,對於更複雜的模型,我們可以利用LIME這樣的「黑盒解釋器」來稍微解釋一下分類器具體是如何工作的。

LIME

LIME是Github上的一個開源軟體包,它允許用戶通過觀察輸入的擾動(比如在我們的例子中,從句中移除單詞)來分析一個特定分類器的預測結果是如何變化的。

從下圖來看它對我們數據集中幾個句子的解釋:

正確分類的災難性辭彙被歸類為「相關」

這個詞對分類的影響似乎不太明顯

不過,我們沒有時間去逐一探索數據集中的數千個樣本。我們要做的是在代表性的測試樣本上運行LIME,以此來分析哪些辭彙對於分類預測的影響更大。這樣,我們就可以像前面一樣獲取到單詞的重要性分數,以驗證模型的預測結果。

Word2Vec:單詞的重要性

模型能夠提取高度相關的詞,這意味著它做出了可解釋的決定。這些辭彙的相關度是最高的,因此我們更願意在實際生產中部署這樣的模型。

八、使用端到端的方式訓練語法特徵

我們已經介紹過如何用快速有效的辦法來生成緊湊的句子嵌入。然而,通過省略辭彙的順序,我們也放棄了語句的所有句法信息。如果簡單的方法給不出令人滿意的結果,那我們就用更為複雜的模型:將整個句子作為輸入並預測標籤,同時無需建立中間表示。一種常見的做法是把句子視為詞向量的序列,如使用Word2Vec,或是GloVe、CoVe等更先進的方法。接下來我們詳細討論。

高效的端到端的訓練體系結構(源)

用於句子分類的卷積神經網路(arxiv.org/abs/1408.5882)訓練速度很快。它作為一種入門級的深度學習架構,能夠很好地解決分類問題。儘管CNN聲名主要源自它在圖像處理方面的出色能力,但在文本相關任務上,它所提供的結果也相當優異。且相比多數複雜的NLP方法(如LSTM、Encoder/Decoder架構等),CNN訓練速度也更快。它能夠保留單詞的順序,很好地學習單詞的序列特徵以及其他有用信息。相對於先前的模型,它可以區分出「Alex eats plants」與「Plants eat Alex」之間差異。

相比先前的方法,該模型的訓練不需更多的工作,但效果卻好得多,準確率高達79.5%!與前面的步驟一樣,下一步也要繼續探索並可視化該模型的預測結果,以驗證它是否為最佳模型。做到這一步,你應該能自己完成這裡的操作。

寫在最後

簡單回顧一下,我們在各個步驟中所用的方法是這樣的:

  • 從一個簡單的模型快速開始
  • 解釋模型的預測
  • 理解模型分類中的錯誤樣本
  • 使用這些知識來決定下一步的部署。

上述八大步驟所用的模型是我們處理短文本時的幾個特定實例,但其背後的解決方法已經廣泛被用在各類NLP問題的實際處理上。

原文鏈接:

blog.insightdatascience.com

weixin.qq.com/r/NDjo8E3 (二維碼自動識別)


推薦閱讀:

自然語言處理透析希拉里和特朗普各自的「演講范兒」
Attention用於NLP的一些小結
python學習之文章數據分析
一篇通俗易懂的word2vec
Model, model告訴我,她到底在想什麼?

TAG:機器學習 | 自然語言處理 | 深度學習DeepLearning |