自然語言工具包 - 文字分類



什麼是文字分類?

文字分類,顧名思義,就是對文字或文件進行分類的方法。但這裡出現了一個問題,為什麼我們需要使用文字分類器?一旦檢查了文件或文字中單詞的使用情況,分類器就能確定應該為其分配什麼類別標籤。

二元分類器

顧名思義,二元分類器將在兩個標籤之間做出決策。例如,正面或負面。在這種情況下,文字或文件要麼是一個標籤,要麼是另一個標籤,但不能同時是兩個標籤。

多標籤分類器

與二元分類器相反,多標籤分類器可以為文字或文件分配一個或多個標籤。

帶標籤與無標籤特徵集

特徵名稱到特徵值的鍵值對映稱為特徵集。帶標籤的特徵集或訓練資料對於分類訓練非常重要,以便它以後可以對無標籤的特徵集進行分類。

帶標籤的特徵集 無標籤的特徵集
它是一個看起來像 (feat, label) 的元組。 它本身就是一個特徵。
它是一個具有已知類別標籤的例項。 如果沒有關聯的標籤,我們可以稱之為例項。
用於訓練分類演算法。 訓練完成後,分類演算法可以對無標籤的特徵集進行分類。

文字特徵提取

文字特徵提取,顧名思義,就是將單詞列表轉換為分類器可用的特徵集的過程。我們必須將我們的文字轉換為“dict”風格的特徵集,因為自然語言工具包 (NLTK) 期望“dict”風格的特徵集。

詞袋 (BoW) 模型

BoW,是NLP中最簡單的模型之一,用於從文字或文件中提取特徵,以便在建模中使用,例如在機器學習演算法中。它基本上從例項的所有單詞構建一個單詞存在特徵集。這種方法背後的概念是,它不關心一個單詞出現的次數或單詞的順序,它只關心該單詞是否存在於單詞列表中。

示例

對於此示例,我們將定義一個名為 bow() 的函式 -

def bow(words):
   return dict([(word, True) for word in words])

現在,讓我們在單詞上呼叫bow()函式。我們將這些函式儲存在名為 bagwords.py 的檔案中。

from bagwords import bow
bow(['we', 'are', 'using', 'tutorialspoint'])

輸出

{'we': True, 'are': True, 'using': True, 'tutorialspoint': True}

訓練分類器

在前面的部分中,我們學習瞭如何從文字中提取特徵。因此,現在我們可以訓練分類器了。第一個也是最簡單的分類器是NaiveBayesClassifier類。

樸素貝葉斯分類器

為了預測給定特徵集屬於特定標籤的機率,它使用貝葉斯定理。貝葉斯定理的公式如下。

$$P(A|B)=\frac{P(B|A)P(A)}{P(B)}$$

這裡,

P(A|B) - 它也稱為後驗機率,即在第二個事件(即B)發生的情況下,第一個事件(即A)發生的機率。

P(B|A) - 它是第一個事件(即A)發生後第二個事件(即B)發生的機率。

P(A), P(B) - 它也稱為先驗機率,即第一個事件(即A)或第二個事件(即B)發生的機率。

為了訓練樸素貝葉斯分類器,我們將使用NLTK中的movie_reviews語料庫。此語料庫有兩個類別的文字,即:posneg。這些類別使在它們上面訓練的分類器成為二元分類器。語料庫中的每個檔案都由兩個組成,一個是正面影評,另一個是負面影評。在我們的示例中,我們將使用每個檔案作為訓練和測試分類器的單個例項。

示例

為了訓練分類器,我們需要一個帶標籤的特徵集列表,它將採用[(featureset, label)]的形式。這裡的featureset變數是一個dict,標籤是featureset的已知類別標籤。我們將建立一個名為label_corpus()的函式,它將獲取一個名為movie_reviews的語料庫,以及一個名為feature_detector的函式,預設為詞袋。它將構建並返回一個{label: [featureset]}形式的對映。之後,我們將使用此對映來建立帶標籤的訓練例項和測試例項列表。

import collections

def label_corpus(corp, feature_detector=bow):
   label_feats = collections.defaultdict(list)
   for label in corp.categories():
      for fileid in corp.fileids(categories=[label]):
         feats = feature_detector(corp.words(fileids=[fileid]))
         label_feats[label].append(feats)
   return label_feats

藉助上述函式,我們將獲得一個{label:fetaureset}對映。現在,我們將定義另一個名為split的函式,它將獲取label_corpus()函式返回的對映,並將每個特徵集列表拆分為帶標籤的訓練例項和測試例項。

def split(lfeats, split=0.75):
   train_feats = []
   test_feats = []
   for label, feats in lfeats.items():
      cutoff = int(len(feats) * split)
      train_feats.extend([(feat, label) for feat in feats[:cutoff]])
      test_feats.extend([(feat, label) for feat in feats[cutoff:]])
   return train_feats, test_feats

現在,讓我們在我們的語料庫(即movie_reviews)上使用這些函式 -

from nltk.corpus import movie_reviews
from featx import label_feats_from_corpus, split_label_feats
movie_reviews.categories()

輸出

['neg', 'pos']

示例

lfeats = label_feats_from_corpus(movie_reviews)
lfeats.keys()

輸出

dict_keys(['neg', 'pos'])

示例

train_feats, test_feats = split_label_feats(lfeats, split = 0.75)
len(train_feats)

輸出

1500

示例

len(test_feats)

輸出

500

我們已經看到,在movie_reviews語料庫中,有1000個pos檔案和1000個neg檔案。我們最終也得到了1500個帶標籤的訓練例項和500個帶標籤的測試例項。

現在讓我們使用其train()類方法訓練NaïveBayesClassifier -

from nltk.classify import NaiveBayesClassifier
NBC = NaiveBayesClassifier.train(train_feats)
NBC.labels()

輸出

['neg', 'pos']

決策樹分類器

另一個重要的分類器是決策樹分類器。在這裡,為了訓練它,DecisionTreeClassifier類將建立一個樹結構。在此樹結構中,每個節點對應一個特徵名稱,分支對應特徵值。向下沿著分支,我們將到達樹的葉子,即分類標籤。

為了訓練決策樹分類器,我們將使用相同的訓練和測試特徵,即train_featstest_feats變數,這些變數是我們從movie_reviews語料庫中建立的。

示例

為了訓練此分類器,我們將呼叫DecisionTreeClassifier.train()類方法,如下所示 -

from nltk.classify import DecisionTreeClassifier
decisiont_classifier = DecisionTreeClassifier.train(
   train_feats, binary = True, entropy_cutoff = 0.8, 
   depth_cutoff = 5, support_cutoff = 30
)
accuracy(decisiont_classifier, test_feats)

輸出

0.725

最大熵分類器

另一個重要的分類器是MaxentClassifier,它也稱為條件指數分類器邏輯迴歸分類器。在這裡,為了訓練它,MaxentClassifier類將使用編碼將帶標籤的特徵集轉換為向量。

為了訓練決策樹分類器,我們將使用相同的訓練和測試特徵,即train_featstest_feats變數,這些變數是我們從movie_reviews語料庫中建立的。

示例

為了訓練此分類器,我們將呼叫MaxentClassifier.train()類方法,如下所示 -

from nltk.classify import MaxentClassifier
maxent_classifier = MaxentClassifier
.train(train_feats,algorithm = 'gis', trace = 0, max_iter = 10, min_lldelta = 0.5)
accuracy(maxent_classifier, test_feats)

輸出

0.786

Scikit-learn分類器

Scikit-learn是最好的機器學習 (ML) 庫之一。它實際上包含各種用途的各種ML演算法,但它們都具有以下相同的擬合設計模式 -

  • 將模型擬合到資料
  • 並使用該模型進行預測

這裡,我們不會直接訪問scikit-learn模型,而是將使用NLTK的SklearnClassifier類。此類是scikit-learn模型的包裝類,使其符合NLTK的Classifier介面。

我們將按照以下步驟訓練SklearnClassifier類 -

步驟1 - 首先,我們將像在以前的配方中一樣建立訓練特徵。

步驟2 - 現在,選擇並匯入Scikit-learn演算法。

步驟3 - 接下來,我們需要使用所選演算法構建SklearnClassifier類。

步驟4 - 最後,我們將使用我們的訓練特徵訓練SklearnClassifier類。

讓我們在下面的Python配方中實現這些步驟 -

from nltk.classify.scikitlearn import SklearnClassifier
from sklearn.naive_bayes import MultinomialNB
sklearn_classifier = SklearnClassifier(MultinomialNB())
sklearn_classifier.train(train_feats)
<SklearnClassifier(MultinomialNB(alpha = 1.0,class_prior = None,fit_prior = True))>
accuracy(sk_classifier, test_feats)

輸出

0.885

測量精確率和召回率

在訓練各種分類器時,我們也測量了它們的準確率。但是除了準確率之外,還有許多其他指標用於評估分類器。這兩個指標是精確率召回率

示例

在此示例中,我們將計算之前訓練的NaiveBayesClassifier類的精確率和召回率。為了實現這一點,我們將建立一個名為metrics_PR()的函式,它將有兩個引數,一個是訓練好的分類器,另一個是帶標籤的測試特徵。這兩個引數與我們在計算分類器準確率時傳遞的引數相同 -

import collections
from nltk import metrics
def metrics_PR(classifier, testfeats):
   refsets = collections.defaultdict(set)
   testsets = collections.defaultdict(set)
   for i, (feats, label) in enumerate(testfeats):
      refsets[label].add(i)
      observed = classifier.classify(feats)
         testsets[observed].add(i)
   precisions = {}
   recalls = {}
   for label in classifier.labels():
   precisions[label] = metrics.precision(refsets[label],testsets[label])
   recalls[label] = metrics.recall(refsets[label], testsets[label])
   return precisions, recalls

讓我們呼叫此函式以查詢精確率和召回率 -

from metrics_classification import metrics_PR
nb_precisions, nb_recalls = metrics_PR(nb_classifier,test_feats)
nb_precisions['pos']

輸出

0.6713532466435213

示例

nb_precisions['neg']

輸出

0.9676271186440678

示例

nb_recalls['pos']

輸出

0.96

示例

nb_recalls['neg']

輸出

0.478

分類器組合和投票

組合分類器是提高分類效能的最佳方法之一。投票是組合多個分類器的最佳方法之一。對於投票,我們需要有奇數個分類器。在下面的Python配方中,我們將組合三個分類器,即NaiveBayesClassifier類、DecisionTreeClassifier類和MaxentClassifier類。

為了實現這一點,我們將定義一個名為voting_classifiers()的函式,如下所示。

import itertools
from nltk.classify import ClassifierI
from nltk.probability import FreqDist
class Voting_classifiers(ClassifierI):
   def __init__(self, *classifiers):
      self._classifiers = classifiers
      self._labels = sorted(set(itertools.chain(*[c.labels() for c in classifiers])))
   def labels(self):
      return self._labels
   def classify(self, feats):
      counts = FreqDist()
      for classifier in self._classifiers:
         counts[classifier.classify(feats)] += 1
      return counts.max()

讓我們呼叫此函式以組合三個分類器並找到準確率 -

from vote_classification import Voting_classifiers
combined_classifier = Voting_classifiers(NBC, decisiont_classifier, maxent_classifier)
combined_classifier.labels()

輸出

['neg', 'pos']

示例

accuracy(combined_classifier, test_feats)

輸出

0.948

從上面的輸出中,我們可以看到組合分類器的準確率高於單個分類器。

廣告

© . All rights reserved.