Natural-language-toolkit-text-classification

提供:Dev Guides
移動先:案内検索

自然言語ツールキット-テキスト分類

テキスト分類とは何ですか?

名前が示すように、テキスト分類は、テキストまたはドキュメントの一部を分類する方法です。 しかし、ここでなぜテキスト分類子を使用する必要があるのか​​という疑問が生じますか? ドキュメントまたはテキストの一部での単語の使用法を調べると、分類子はどのクラスラベルを割り当てるかを決定できます。

バイナリ分類子

名前が示すように、バイナリ分類子は2つのラベルを決定します。 たとえば、正または負。 この場合、テキストまたはドキュメントは、どちらか一方のラベルにすることも、両方にすることもできません。

マルチラベル分類子

バイナリ分類子とは逆に、マルチラベル分類子は1つ以上のラベルをテキストまたはドキュメントに割り当てることができます。

ラベル付きとラベルなしの機能セット

機能名から機能値へのキーと値のマッピングは、機能セットと呼ばれます。 ラベル付けされたフィーチャセットまたはトレーニングデータは、分類のトレーニングにとって非常に重要であり、後でラベル付けされていないフィーチャセットを分類できるようになります。

Labeled Feature Set Unlabeled Feature Set
It is a tuple that look like (feat, label). It is a feat itself.
It is an instance with a known class label. Without associated label, we can call it an instance.
Used for training a classification algorithm. Once trained, classification algorithm can classify an unlabeled feature set.

テキスト特徴抽出

テキストの特徴抽出は、その名前が示すように、単語のリストを分類子が使用できる特徴セットに変換するプロセスです。 Natural Language Tool Kit(NLTK)は ‘dict’ スタイルの機能セットを想定しているため、テキストを ‘dict’ スタイルの機能セットに変換する必要があります。

Bag of Words(BoW)モデル

NLPで最も単純なモデルの1つであるBoWを使用して、テキストまたはドキュメントの一部から特徴を抽出し、MLアルゴリズムなどのモデリングで使用できるようにします。 基本的には、インスタンスのすべての単語から単語の存在機能セットを構築します。 この方法の背後にある概念は、単語の出現回数や順序については関係なく、単語が単語リストに存在するかどうかのみを気にするということです。

この例では、bow()という名前の関数を定義します-

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

次に、* bow()*関数を単語で呼び出します。 この関数をbagwords.pyという名前のファイルに保存しました。

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

出力

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

トレーニング分類子

前のセクションでは、テキストから特徴を抽出する方法を学びました。 これで、分類子をトレーニングできます。 最初で最も簡単な分類子は NaiveBayesClassifier クラスです。

単純ベイズ分類器

特定の機能セットが特定のラベルに属する確率を予測するには、ベイズの定理を使用します。 ベイズの定理の式は次のとおりです。

ここに、

  • P(A | B)*-事後確率とも呼ばれます。 最初のイベントの確率、つまり その2番目のイベント、つまり Bが発生しました。
  • P(B | A)*-2番目のイベントの確率です。 Bは、最初のイベントの後に発生します。 Aが発生しました。
  • P(A)、P(B)*-事前確率とも呼ばれます。 最初のイベントの確率、つまり Aまたは2番目のイベント、つまり Bが発生します。

ナイーブベイズ分類器をトレーニングするために、NLTKの movie_reviews コーパスを使用します。 このコーパスには、 posneg という2つのカテゴリのテキストがあります。 これらのカテゴリは、それらでトレーニングされた分類器をバイナリ分類器にします。 コーパス内のすべてのファイルは2つで構成され、1つはポジティブな映画レビュー、もう1つはネガティブな映画レビューです。 この例では、分類子のトレーニングとテストの両方で、各ファイルを単一のインスタンスとして使用します。

分類器をトレーニングするには、[( featureset、label )]という形式のラベル付き機能セットのリストが必要です。 ここで、 featureset 変数は dict であり、labelは featureset の既知のクラスラベルです。 * movie_reviews というコーパスを使用する label_corpus()という名前の関数と、デフォルトで *bag of words になる feature_detector という名前の関数を作成します。 これは、フォーム\ {label:[featureset]}のマッピングを作成して返します。 その後、このマッピングを使用して、ラベル付きのトレーニングインスタンスとテストインスタンスのリストを作成します。

コレクションをインポート

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 という名前のもう1つの関数を定義します。これは、* 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']

決定木分類器

もう1つの重要な分類子は、決定木分類子です。 ここでそれを訓練するために DecisionTreeClassifier クラスはツリー構造を作成します。 このツリー構造では、各ノードは機能名に対応し、ブランチは機能値に対応しています。 そして枝を下って、私たちは木の葉に行きます、すなわち 分類ラベル。

決定木分類器をトレーニングするために、同じトレーニングとテスト機能を使用します。 train_feats および test_featsmovie_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

最大エントロピー分類子

もう1つの重要な分類子は MaxentClassifier で、条件付き指数分類子*または*ロジスティック回帰分類子*とも呼ばれます。 ここでそれをトレーニングするために、 *MaxentClassifier クラスは、ラベル付けされた特徴セットをエンコーディングを使用してベクトルに変換します。

決定木分類器をトレーニングするために、同じトレーニングとテスト機能を使用します。 * train_feats と *test_featsmovie_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分類子

最良の機械学習(ML)ライブラリの1つはScikit-learnです。 それは実際にはさまざまな目的のためのあらゆる種類のMLアルゴリズムを含んでいますが、それらはすべて次のように同じフィット設計パターンを持っています-

  • モデルをデータに適合させる
  • そのモデルを使用して予測を行います

ここでは、scikit-learnモデルに直接アクセスするのではなく、NLTKの SklearnClassifier クラスを使用します。 このクラスは、NLTKのClassifierインターフェースに準拠させるためのscikit-learnモデルのラッパークラスです。

*Sk​​learnClassifier* クラスをトレーニングするには、次の手順に従います-
  • ステップ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

精度と再現率の測定

さまざまな分類子をトレーニングしながら、それらの精度も測定しました。 しかし、正確性とは別に、分類子を評価するために使用される他の多くのメトリックがあります。 これらのメトリックのうちの2つは、「精度」と「再現率」です。

この例では、以前にトレーニングしたNaiveBayesClassifierクラスの精度と再現率を計算します。 これを実現するために、2つの引数をとるmetrics_PR()という名前の関数を作成します。1つはトレーニング済み分類子で、もう1つはラベル付きテスト機能です。 両方の引数は、分類子の精度を計算するときに渡したものと同じです-

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

分類子と投票の組み合わせ

分類子を組み合わせることは、分類パフォーマンスを改善する最良の方法の1つです。 そして投票は、複数の分類子を組み合わせる最良の方法の1つです。 投票には、奇数の分類子が必要です。 次のPythonレシピでは、3つの分類子、つまり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()

この関数を呼び出して、3つの分類子を組み合わせて精度を見つけましょう-

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

上記の出力から、結合された分類子が個々の分類子よりも高い精度を得たことがわかります。