圖文並茂,用 Python 實現文本分類

前言

目前網絡上已經有大量的文本數據存在,並且每天還有越來越多的文本以電子郵件、社交媒體帖子、聊天內容、網站和文章的形式生成。這些文本都是豐富的信息源。但由於文本的非結構化性質,理解和分析它們是非常困難和耗時的。

因此,大多數公司無法利用這一寶貴的信息來源。而這正好是文本分類等自然語言處理(NLP)的用武之地。

什麼是文本分類?

文本分類,也稱爲文本分組或文本標記,是將文本文檔分配給一個或多個類別的過程。它能夠以快速、廉價的方式自動構建所有類型的相關文本。通過對文本數據進行分類,我們可以快速瞭解趨勢,並縮小範圍進行進一步分析。

假設你入職了一家公司,職責是幫助公司整理客戶評論。如果公司客戶遍佈全球,並且有多種語言編寫的評論,那麼你需要根據語言將評論進行劃分,這有助於你進行下一步工作。

儘管好評令人振奮和滿足,但它們很少包含需要立即解決的緊迫問題。所以最好進行情感分析並將評論分爲正面和負面。之前做的按語言分類正好有助於創建特定語言的情感分析模型。

一旦有了負面評論,你可以根據裏面提到的功能 / 產品對其進行進一步分類。這可以讓不同的團隊輕鬆找到相關的評論,並找出他們做的不對的地方進而進行改進。

文本分類是如何工作的?

有兩種廣泛的文本分類方法:

_手動文本分類_需要人工註釋員,他們通讀文本文檔的內容並對其進行標記。如果你認爲這種方法只會在處理大量文本時產生問題。其實是不對的,有兩個原因:

實時性

速度慢是其中一個問題,手動分類會妨礙我們快速識別和應對關鍵情況。舉個例子,假設一個雲服務商或一個 API 宕機,如果一個人按順序查看客戶支持記錄,我們可能需要很長一段時間才能發現他們的服務宕機。

一致性

哪怕是一生中最好的時機,人類也是不完美的。由於睡眠不足、無聊、分心等因素,人類容易犯錯誤。這些因素可能導致分類不一致。對於關鍵的應用程序,這些失誤可能會讓公司損失成千上萬的錢。

除了這些缺點之外,人工時間的成本遠遠高於在雲服務器上運行 Python 腳本。因此,應用自然語言處理和其他人工智能技術進行自動文本分類是大多數情況下的最佳選擇。自動分類速度更快,成本效益更高。最重要的是,一旦文本分類模型訓練到令人滿意的程度,它的性能能一直保持。

有很多方法可以自動對文本文檔進行分類,一般歸類爲以下三種類型:

基於規則的方法

基於規則的方法使用一組手動創建的語言規則對文本進行分類。這些規則由每個類別的一個模式或一組模式組成。一種非常簡單的方法是根據特定類別單詞的出現情況對文檔進行分類。

假設你想把新聞文章分爲兩類:商業科學。要做到這一點,你需要創建兩個單詞列表,對每個類別進行分類。例如,你可以選擇高盛、摩根士丹利、蘋果等機構的名稱用於商業分類,選擇 NASA、科學家、研究人員等詞彙用於科學分類。

現在,當你想對一篇新聞文章進行分類時,基於規則的分類器將統計與商業相關的詞和與科學相關的詞的數量。如果與商業相關的單詞數量大於與科學相關的單詞數量,則文章將被歸類爲商業,反之亦然。

舉個例子,基於規則的分類器將新聞標題 "國際空間站:NASA 計劃如何摧毀它" 歸類爲科學,因爲有一個與科學相關的詞——'NASA',而沒有與商業相關的詞。

使用基於規則的系統的最大優點是,外行很容易理解。一旦創建了一個基本系統,它就可以隨着時間的推移而逐步改進。但這種優勢的另一方面是,開發人員需要對領域有深入的瞭解才能創建規則。此外,基於規則的分類方法不能很好地擴展,在沒有適當測試的情況下添加新規則可能會影響舊規則的結果。

基於機器學習的方法

你可以選擇一種基於機器學習的方法,使用過去的經驗自動學習規則,而不是手動定義規則。基於機器學習的分類器使用帶標籤的示例作爲訓練數據來學習單詞 / 短語和標籤之間的關聯,即類別。

聽起來很容易解決,但在訓練機器學習分類器之前,有一個問題需要解決,那就是特徵提取。計算機不像我們那樣理解文本,它們只理解 0 和 1。比如在計算機視覺問題的場景中,圖像以數字的形式存儲在內部,表示各個像素的值。

但文本並非如此。因此,訓練 NLP 分類器的第一步是將文本轉換爲數字向量表示。最常用的文本嵌入方法之一是詞袋法。它創建一個向量,統計每個單詞在預定義詞典中的出現次數。

假設你將字典定義爲: "(What,a,sunny,serene,Beauty,day,night)" ,你想創建 "What a serene night" 的嵌入詞向量。你會得到以下的向量表示法:(1,1,0,1,0,0,0,1)

生成所有帶標籤文本文檔的向量表示後,可以使用它們來訓練分類器。文本文檔的向量帶着正確的類別傳遞給分類器。模型學習文本中不同語言特徵與類別之間的關聯:

一旦模型被訓練到滿足需要的性能標準,它就可以用來做出準確的預測。使用相同的特徵提取方法創建新文本文檔的向量表示,然後分類模型使用這些特徵向量來預測文檔的類別。

基於機器學習的文本分類方法通常比基於規則的分類器更準確。除此之外,機器學習分類器更容易擴展,因爲你可以簡單地添加新的訓練示例來更新模型。機器學習分類器的唯一問題是它們很難理解和調試。因此,如果出現問題,可能很難找出問題的原因。

混合方法

混合文本分類方法結合了上面兩個方法的優點。它們將機器學習分類器的泛化能力與易於理解和調整的基於規則的方法相結合。受益於機器學習模型,混合方法可以學習複雜的規則,任何衝突的分類或不穩定的行爲都可以使用規則修復。

例如,根據行業對金融新聞文章進行分類,如製藥、金融、汽車、採礦等。要做到這一點,你需要創建一個混合系統。首先,訓練一個命名實體識別模型,從新聞文章中提取公司名稱。然後,創建每個部門的公司列表。做完這兩樣,就可以創建一個合格的分類器。

用 Transformers&scikit learn 對新聞標題進行分類

首先,需要安裝 spaCy 包,spacy-sentence-bert[1] 和 scikit-learn[2] 模塊。

數據從這裏 [3] 獲取。

你將使用我們一些舊的谷歌新聞數據。新聞數據以 JSONL 格式存儲。通常,你可以使用 read_json 方法將 JSONL 文件加載到 DataFrame 中,並使用 lines=True 參數,但此處我們的數據結構稍微有點不一樣。

每行數據都存儲在一個對象中({'item':})。如果你嘗試使用 read_json 方法直接加載它,它會將所有內容作爲一列加載。

import pandas as pd

df = pd.read_json('data.json'lines=True)
print(df)

要解決這個問題,可以像讀取普通文本文件一樣讀取該文件,並使用 json.loads 方法來創建字典列表。

import

data = []
with open('data.json''r') as f:
  data = f.readlines()
  
data = [json.loads(item)['Item'] for item in data]

print(data[:2])

還有一個問題需要解決. 標題的屬性值存儲在它自己的對象中。不用擔心,可以通過進一步的字典操作來解決。

for i in range(len(data)):
  for key in data[i].keys():
    data[i][key] = data[i][key]["S"]
    
print(data[:2])

現在你可以從新聞數據中創建一個 DataFrame 了。

df = pd.DataFrame(data)

print(df.head())

我們來看下所有的主題標籤。

print(df.topic.unique())

## OUTPUT
## array(['ENTERTAINMENT', 'BUSINESS', 'NATION', 'SPORTS', 'WORLD',
##     'TECHNOLOGY', 'HEALTH', 'SCIENCE'], dtype=object)

有些屬性其實不需要,比如 country, lang, or cleaned_url。主題標籤中的——“WORLD”和 “NATION” 的信息量不大,因爲它們的定義非常寬鬆。所以,你可以把它們 drop 掉。

#drop columns
df = df[['topic','title']]

#drop 'NATION' and 'WORLD" labels
data = df[df['topic'] != 'NATION' or df['topic'] != 'WORLD']

我們再檢查下缺失值並刪除不完整的條目。

print(data.isnull().sum())

## OUTPUT
## topic    0
## title    1
## dtype: int64

data = data.dropna()

接下來,應該看看我們爲每個類別提供了多少訓練示例。

counts = data['topic'].value_counts()
counts.plot(kind='bar'legend=False, grid=True, figsize=(8, 5))

兩大類超過 35 萬篇文章,甚至小的列也有大約 4 萬組數據!

再看看標題長度的分佈情況?

import numpy as np

lens = data.title.str.len()
lens.hist(bins = np.arange(0,200,5))

看起來還算 “正常”。

不開玩笑的說,當使用最先進的 BERT transformer 模型來創建向量表示時,我建議使用可用數據集的子集來訓練模型。

for topic in topics:
  temp_df = data[data['topic'] == topic][:5000]
  df = pd.concat([df, temp_df])

現在,你可以加載 BERT 句子轉換器,併爲標題創建向量嵌入。

import spacy_sentence_bert

# load one of the models listed at https://github.com/MartinoMensio/spacy-sentence-bert/
nlp = spacy_sentence_bert.load_model('en_stsb_distilbert_base')
df['vector'] = df['title'].apply(lambda x: nlp(x).vector)

讓我們把數據分成訓練集和測試集。

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(df['vector'].tolist(), df['topic'].tolist()test_size=0.33, random_state=42)

最後,可以選擇多個機器學習分類器進行訓練。

from sklearn.svm import SVC

clf = SVC(gamma='auto')
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
print(accuracy_score(y_test, y_pred))

## OUTPUT
## 0.8392929292929293
from sklearn.ensemble import RandomForestClassifier

clf = RandomForestClassifier(max_depth=9, random_state=0)
clf.fit(X_train, y_train)

y_pred = clf.predict(X_test)
print(accuracy_score(y_test, y_pred))

## OUTPUT
## 0.7471717171717172

支持向量分類器(SVM)的性能位居榜首。你可以用它來預測新新聞標題的主題。

讓我們在谷歌新聞的一堆新聞標題上試一試:

headlines = ["Scientists Figured Out How Much Exercise You Need to 'Offset' a Day of Sitting",
 "Marlee Matlin On Her Career And 'CODA' — The Actor's Side – Deadline",
 "Increasing mental health issues a symptom of Victoria's lockdown",
 'Philippines polio outbreak over: UN',
 "Sophie, Countess of Wessex opens up about menopause: ‘It's like somebody's just gone and taken your brain'",
 'Bill Gates tells why he prefers Android mobile over iPhone',
 "'A weight has been lifted' Edinburgh pubs and restaurants react to hospitality rules easing",
 "Mysterious Signal Flashing From Galaxy's Core Baffle Scientists; Where Is There Source of This Radio Waves?",
 "'Tears in their eyes': World erupts over All Blacks' beautiful Maradona tribute",
 "'Packed in like sardines'"]

topics = ['SCIENCE',  'ENTERTAINMENT',  'HEALTH',
 'HEALTH',  'ENTERTAINMENT',  'TECHNOLOGY',  'BUSINESS',
 'SCIENCE',  'SPORTS',  'ENTERTAINMENT']
for headline, topic in zip(headlines, topics):
  print(headline)
  print(f"True Label: {topic}, Predicted Label:{clf.predict(nlp(headline).vector.reshape(1, -1))[0]} \n")

結論

現在你應該知道什麼是文本分類,它是如何工作的,以及如何訓練自己的機器學習文本分類器。那麼神經網絡用起來會怎樣呢?這是個好問題。其實儘管神經網絡很好,但對於這項任務來說,卻並不是必要的。支持向量機和神經網絡都能逼近非線性決策邊界,並且它們都能在同一數據集上獲得相當優秀的結果。神經網絡可能在性能上稍有領先,但需要更多的計算能力、訓練數據和時間。

另一方面,支持向量機能夠基於唯一的支持向量可靠地識別決策邊界。因此,你只需要使用要達到類似性能的神經網絡所需的一小部分數據來訓練 SVM 分類器。當然,如果性的任何微小提升對你來說都非常重要,那麼可以使用神經網絡。

參考資料

[1]

spacy-sentence-bert: https://github.com/MartinoMensio/spacy-sentence-bert

[2]

scikit-learn: https://scikit-learn.org/

[3]

這裏: https://drive.google.com/drive/folders/1CNVlbyz7Wx_6Ex73R5reNAny04f0p8Tq

[4]

參考原文: https://newscatcherapi.com/blog/how-to-classify-text-with-python-transformers-and-scikit-learn

Python 開發精選 分享 Python 技術文章、資源、課程、資訊。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/k-MNNunuQa5sedHQ6QvdUA