指南 | 手把手教你解決90%的NLP問題
文本數據到處都是
無論是一家已成立的公司,還是正在開發(fā)一項新服務,都可以利用文本數據來驗證、改進和擴展產品的功能。從文本數據中提取語義和學習的科學是一個被稱為自然語言處理(NLP)的活躍研究課題。
NLP每天都有新的重要的進展,這是一個非常大的領域。然而,在與數百家公司合作之后,Insight團隊發(fā)現一些關鍵的實際應用比其他應用出現得更頻繁:
- 確定不同的用戶/客戶群體(例如預測客戶流失、終身價值、產品偏好)
- 準確檢測和提取不同類別的反饋(正面和負面的評論/意見,屬性,如衣服尺寸/合身度…)
- 按意圖將文本分類(例如:請求基本幫助、緊急問題)
雖然在網上有許多NLP的論文和教程,但我們發(fā)現很難找到指導方針和技巧來從根本上有效地解決這些問題。
這篇文章有什么用?
在一年領導了數百個項目,并從美國各地的頂級團隊獲得建議之后,我們寫了這篇文章來解釋如何構建機器學習解決方案來解決上述問題。我們將從最簡單可行的方法開始,然后轉向更細微的解決方案,如特征工程、詞向量和深度學習。
讀完這篇文章,你會知道:
- 收集、準備和檢查數據
- 建立簡單的模型開始,并過渡到深入學習,如果必要的話
- 解釋和理解你的模型,以確保你實際捕獲的是信息而不是噪音
我們寫這篇文章是作為一個循序漸進的指南,它還可以作為高效標準方法的高層次概述。
第一步: 收集數據
數據源的樣例
每一個機器學習問題都是從數據開始的,比如電子郵件、帖子或tweet列表。常見的文本信息來源包括:
- 產品評論(亞馬遜,Yelp,各種應用商店)
- 用戶生成內容(tweet、Facebook帖子、StackOverflow問題)
- 故障排除(客戶請求、支持票、聊天日志)
“Disasters on Social Media” dataset
“社交媒體災難”數據集
對于本文,我們將使用圖8提供的數據集,名為“社交媒體上的災難”,其中:
貢獻者們查看了1萬多條推文,這些推文都經過了各種各樣的搜索,比如“著火”、“隔離”和“混亂”,然后指出這條推文是否指的是災難事件(而不是帶有這個詞的笑話、電影評論或其他非災難性的東西)。
我們的任務是檢測哪些tweet是關于災難性事件的,而不是與之相關的主題,比如電影。為什么?一種潛在的應用可能是,在不理會對Adam Sandler最新電影的評論的情況下,只向執(zhí)法官員通報緊急情況。這項任務的一個特殊挑戰(zhàn)是,這兩個類都包含用于查找tweet的相同搜索詞,因此我們將不得不使用更細微的差異來區(qū)分它們。
在本文的其余部分,我們將把關于災難的tweet稱為“災難”,而關于其他任何事情的tweet稱為“無關”。
標簽
我們已經標記了數據,所以我們知道哪些tweet屬于哪些類別。正如Richard Socher在下面所概述的,找到和標記足夠的數據來訓練模型通常更快、更簡單、更便宜,而不是試圖優(yōu)化一個復雜的無監(jiān)督方法。

第二步: 數據清洗
我們遵循的第一條規(guī)則是:“你的模型永遠只會和你的數據一樣好。”
數據科學家的關鍵技能之一是知道下一步應該是處理模型還是數據。一個好的經驗法則是先查看數據,然后整理它。一個干凈的數據集將允許模型學習有意義的特征,而不會在不相關的噪聲上過擬合。
這里有一個清單,可以用來清理你的數據:
- 刪除所有不相關的字符,例如任何非字母數字字符
- Tokenize通過將文本分隔成單個單詞來實現文本的標記
- 刪除不相關的單詞,比如twitter上提到的“@”或url
- 將所有字符轉換為小寫,以便對“hello”、“hello”和“hello”等單詞一視同仁
- 考慮將拼寫錯誤或交替拼寫的單詞組合成一個表示(例如“cool”/“kewl”/“cooool”)
- 考慮詞型還原(將“am”、“are”和“is”等單詞簡化為“be”等常見形式)
在遵循這些步驟并檢查其他錯誤之后,我們可以開始使用干凈的、有標記的數據來訓練模型!
第三步:找一個好的數據表示
機器學習模型以數值作為輸入。例如,處理圖像的模型采用矩陣表示每個顏色通道中的每個像素的強度。
用數字矩陣表示的笑臉
我們的數據集是一個句子列表,所以為了讓我們的算法從數據中提取模式,我們首先需要找到一種方法,以我們的算法能夠理解的方式來表示它,即作為一個數字列表。
One-hot編碼(詞袋)
表示計算機文本的一種自然方法是將每個字符單獨編碼為一個數字。如果我們要將這個簡單的表示形式提供給分類器,那么它就必須僅基于我們的數據從零開始學習單詞的結構,這對于大多數數據集來說是不可能的。我們需要使用更高層次的方法。
例如,我們可以為數據集中所有惟一的單詞構建一個詞匯表,并為詞匯表中的每個單詞關聯一個惟一索引。然后,每個句子都被表示為一個列表,這個列表與我們詞匯表中不同單詞的數量一樣長。在這個列表的每個索引處,我們標記給定單詞在我們的句子中出現的次數。這稱為詞袋模型,因為它是一個完全忽略句子中單詞順序的表示。如下圖所示。
把句子表示成詞袋。左邊是句子,右邊是描述。向量中的每個索引表示一個特定的單詞。
嵌入的可視化
在“社交媒體災難”的例子中,我們的詞匯量大約有20000個單詞,這意味著每個句子都將被表示為一個長度為20000的向量。向量中大部分都是0,因為每個句子只包含詞匯表的一個非常小的子集。
為了查看我們的嵌入是否捕獲了與我們的問題關的信息(即tweet是否與災難有關),將它們可視化并查看類之間是否有很好的分隔是一個好主意。由于詞匯表通常非常大,并且不可能在20,000個維度中可視化數據,因此PCA等技術將幫助將數據投射到兩個維度。下圖所示。
詞袋嵌入的可視化
這兩個類看起來沒有很好地分離,這可能是我們的嵌入的一個特性,或者僅僅是維數減少的一個特性。為了了解詞袋特征是否有用,我們可以訓練一個基于詞袋特征的分類器。
第四步: 分類
當第一次處理一個問題時,一般的最佳實踐是從能夠解決該工作的最簡單的工具開始。每當涉及到對數據進行分類時,由于其通用性和可解釋性,最受歡迎的是Logistic Regression。它的訓練非常簡單,結果是可解釋的,因為你可以很容易地從模型中提取最重要的系數。
我們將數據分成兩個部分,一個是用于擬合模型的訓練集,另一個是測試集,以查看它對不可見數據的泛化程度。經過訓練,我們得到了75.4%的準確率。還可以!猜測出現最多的類別(“無關緊要”)只會給我們57%的答案。然而,即使75%的精度已經足夠滿足我們的需求,我們不能在不理解模型的情況下就發(fā)布模型。
第五步:檢查
混淆矩陣
第一步是了解我們的模型所犯錯誤的類型,以及哪些錯誤是最不可取的。在我們的示例中,false positive 將不相關的tweet分類為災難,false negative 將災難分類為不相關的tweet。如果我們的首要任務是對每一個潛在的事件做出反應,我們就會想要降低我們的false negative 。然而,如果我們在資源上受到限制,我們可能會優(yōu)先考慮較低的假陽性率,以減少虛警。將這些信息可視化的一個好方法是使用混淆矩陣,它將我們的模型做出的預測與真實的標簽進行比較。理想情況下,矩陣應該是一條從左上角到右下角的對角線(我們的預測與事實完全吻合)。
混淆矩陣(綠色表示比例高,藍色表示比例低)
我們的分類器創(chuàng)建的假陰性比假陽性多(按比例)。換句話說,我們的模型最常見的錯誤是不準確地將災難分類為無關緊要的。如果假陽性代表執(zhí)法的高成本,對我們的分類器,這可能是一個很好的偏見。
解釋我們的模型
為了驗證我們的模型并解釋它的預測,很重要的是看看它使用哪些詞匯來做決策。如果我們的數據是有偏差的,我們的分類器會在樣本數據中做出準確的預測,但是模型在現實世界中不能很好地推廣。在這里,我們?yōu)闉碾y類和無關類繪制最重要的單詞。由于我們只需要提取模型用于預測的系數并對其進行排序,因此用詞袋模型和邏輯回歸來繪制單詞重要性圖非常簡單。
詞袋:單詞重要性
我們的分類器正確地選擇了一些模式(廣島,大屠殺),但顯然似乎在一些無意義的術語上過擬合(heyoo, x1392)。現在,我們的詞袋模型正在處理大量不同單詞的詞匯,并且平等地對待所有單詞。然而,其中一些詞匯非常頻繁,而且只會對我們的預測產生干擾。接下來,我們將嘗試一種表示句子的方法來解釋單詞的頻率,看看我們能否從數據中獲取更多的信號。
第6步:詞匯結構計數
TF-IDF
為了幫助我們的模型更多地關注有意義的單詞,我們可以在我們的詞袋模型上使用TF-IDF score (Term Frequency, Inverse Document Frequency)。TF-IDF根據單詞在我們的數據集中的稀有程度來衡量單詞,對過于頻繁且只會增加噪音的單詞進行減弱。這是我們新的嵌入的PCA投影。
TF-IDF嵌入可視化
從上面我們可以看到,這兩種顏色的區(qū)別更加明顯。這將使我們的分類器更容易地將兩個組分開。讓我們看看這是否會帶來更好的性能。在我們的新嵌入上訓練另一個邏輯回歸,我們得到了76.2%的準確率。
非常輕微的改善。我們的模型是否開始學習更重要的單詞?如果我們在防止模型“作弊”的同時獲得了更好的結果,那么我們就可以真正地將該模型視為一個升級。
TF-IDF:單詞重要性
選到到的單詞看起來更相關了!盡管我們測試集上的準確率只增加了一點點,但是我們對我們的模型所使用的術語有了更多的信心,因此在一個與客戶交互的系統中部署它會更舒服。
第7步:語義的威力
Word2Vec
我們最新的模型能夠識別高頻詞。然而,如果我們部署這個模型,很有可能會遇到以前在我們的訓練集中沒有見過的單詞。之前的模型不能準確地對這些tweet進行分類,即使在訓練期間看到了非常相似的單詞。
為了解決這個問題,我們需要捕捉單詞的語義,這意味著我們需要理解像“good”和“positive”這樣的單詞要比“apricot”和“continent”更接近。我們用來幫助我們捕捉語義的工具叫做Word2Vec。
使用預訓練的單詞
Word2Vec是一種為單詞尋找連續(xù)嵌入的技術。它通過閱讀大量的文本和記憶在相似的語境中出現的單詞來學習。在對足夠的數據進行訓練后,它為詞匯表中的每個單詞生成一個300維的向量,具有相似含義的單詞彼此之間距離更近。
這篇論文的作者(https://arxiv.org/abs/1301.3781)公開了一個模型的源代碼,這個模型是在一個非常大的語料庫上預先訓練的,我們可以利用這個語料庫將一些語義知識包含到我們的模型中。可以在與本文關聯的repository中找到預先訓練好的向量。
語義級別的表示
為我們的分類器獲得一個句子嵌入的快速方法是平均我們句子中所有單詞的Word2Vec得分。這是一個詞袋的方法,就像以前一樣,但是這次我們只丟失了我們句子的語法,而保留了一些語義信息。
Word2Vec句子的嵌入
使用之前的技術可視化的我們的新嵌入:
Word2Vec嵌入可視化
這兩組顏色在這里看起來更加分離,我們的新嵌入應該有助于我們的分類器找到這兩個類之間的分離。經過第三次對同一模型的訓練(Logistic回歸),我們得到的準確率為77.7%,是我們目前最好的結果!是時候檢查我們的模型了。
復雜性和可解釋性的權衡
由于我們的嵌入不像之前的模型中那樣以每個單詞一維的向量來表示,所以很難看出哪些單詞與我們的分類最相關。雖然我們仍然可以訪問邏輯回歸的系數,但它們與嵌入的300個維度有關,而不是與單詞的索引有關。
對于如此低的精確度,失去所有的可解釋性似乎是一個艱難的權衡。但是,對于更復雜的模型,我們可以利用黑匣子解釋器,比如LIME,以便深入了解分類器的工作原理。
LIME
LIME可在Github上獲得通過一個開源包。黑盒解釋器允許用戶通過擾動輸入(在我們的例子中是從句子中刪除單詞)并查看預測如何變化來解釋任何分類器對一個特定示例的決策。
讓我們從我們的數據集中看一些句子的解釋。

選擇正確的災難詞匯來分類為“相關”。

在這里,單詞對分類的貢獻似乎不那么明顯。
然而,我們沒有時間研究數據集中的數千個示例。相反,我們要做的是對一個具有代表性的測試用例樣本運行LIME,并查看哪些單詞會不斷出現,成為強大的貢獻者。使用這種方法,我們可以得到單詞重要性評分,就像我們之前的模型一樣,并驗證我們的模型的預測。
Word2Vec: 單詞重要性
看起來這個模型選擇了高度相關的詞匯,這意味著它似乎做出了可以理解的決定。在所有之前的模型中,這些似乎是最相關的詞匯,因此我們更愿意將它們部署到生產環(huán)境中。
第8步:利用語義,使用端到端的方法
我們已經介紹了生成密集的語句嵌入的快速而有效的方法。然而,通過忽略單詞的順序,我們丟棄了我們句子的所有語法信息。如果這些方法不能提供足夠的結果,你可以使用更復雜的模型,它將整個句子作為輸入并預測標簽,而不需要構建中間表示。一種常見的方法是使用Word2Vec或更近期的方法如GloVe或CoVe將一個句子視為單個單詞向量的序列。這就是我們下面要做的。
高效的端到端的結構
Convolutional Neural Networks for Sentence Classification訓練非常快,是一種入門級的深度學習架構。而卷積神經網絡(CNN)主要是圖像數據性能著稱,他們在文本相關的任務上也能提供優(yōu)秀的結果。和通常最復雜的NLP訓練方法(如[LSTMs]和編碼器/解碼器架構更快。這個模型保存單詞的順序,并學習有價值的信息,以及哪些單詞序列可以預測我們的目標類。與之前的模型相反,它可以區(qū)分“Alex eats plants”和“Plants eat Alex”。
與以前的方法相比,訓練這個模型并不需要更多的工作,并為我們提供了一個比以前的方法更好的模型,獲得79.5%的準確率!與上面的模型一樣,下一步應該是使用我們描述的方法探索和解釋預測,以驗證它確實是部署到用戶的最佳模型。到目前為止,你應該已經習慣了自己處理這個問題。
要點總結
下面是我們成功使用的方法的快速回顧:
- 從一個快速簡單的模型開始
- 解釋其預測
- 了解它正在犯的錯誤
- 使用這些知識來指導下一步,無論是處理數據還是更復雜的模型。