LoginSignup
11
10

More than 5 years have passed since last update.

【翻訳】scikit-learn 0.18 チュートリアル テキストデータの操作

Last updated at Posted at 2016-12-27

http://scikit-learn.org/0.18/tutorial/text_analytics/working_with_text_data.html をgoogle翻訳した
scikit-learn 0.18 チュートリアル 目次 / 前のチュートリアル


テキストデータの操作

このガイドの目的は、1つの実用的なタスクに関する主要な scikit-learn ツールのいくつかを探究することです:20の異なるトピックに関するテキストドキュメント(ニュースグループの投稿)の分析。
このセクションでは、以下の方法を説明します。

  • ファイルの内容とカテゴリをロードする
  • 機械学習に適した特徴ベクトルを抽出する
  • カテゴリ化を行う線形モデルを訓練する
  • グリッド探索戦略を使用して、特徴抽出コンポーネントと分類器の両方の良好な構成を見つける

チュートリアルセットアップ

このチュートリアルを始めるには、最初にscikit-learnと必要なすべての依存関係をインストールする必要があります。
詳細およびシステムごとの指示については、インストール手順のページを参照してください。
このチュートリアルのソースは、scikit-learnフォルダ内にあります:

scikit-learn/doc/tutorial/text_analytics/

チュートリアルフォルダには、次のフォルダが含まれている必要があります。

  • *.rstファイル - sphinxで書かれたチュートリアル文書のソース
  • data - チュートリアルで使用されたデータセットを入れるためのフォルダ
  • skeletons - 練習問題の不完全なサンプルスクリプト
  • solutions - 演習の解決策

ハードドライブ上のどこかに sklearn_tut_workspace という新しいフォルダに skeltons をコピーしましょう。オリジナルのスケルトンを元のままにして、このエクササイズではコピーしたファイルを編集します:

% cp -r skeletons work_directory/sklearn_tut_workspace

機械学習にはデータが必要です。各 $TUTORIAL_HOME/data サブフォルダに移動し、そこから fetch_data.py スクリプトを実行します(最初に読み込んだ後に)。
例えば:

% cd $TUTORIAL_HOME/data/languages
% less fetch_data.py
% python fetch_data.py

20のニュースグループデータセットを読み込む

データセットは「20個のニュースグループ」と呼ばれます。ウェブサイト から引用された公式の記述はここにあります:

20のニュースグループデータセットは、20のニュースグループにまたがって(ほぼ)均等に分割された約20,000のニュースグループ文書の集合です。われわれの知る限りでは、もともと彼の論文「Newsweeder:ネットニュースをフィルタリングすることを学ぶ」のためにケン・ラングによって収集されましたが、このコレクションには明示的に言及していません。 20のニュースグループのコレクションは、テキスト分類やテキストクラスタリングなどの機械学習技術のテキストアプリケーションの実験用の一般的なデータセットになっています。

以下では、scikit-learnの20のニュースグループに組み込みのデータセットローダーを使用します。また、Webサイトから手動でデータセットをダウンロードし、sklearn.datasets.load_files 関数を使用して、圧縮されていないアーカイブフォルダの 20news-bydate-train サブフォルダを指定することもできます。
この最初の例の実行時間を短縮するために、データセットで使用可能な20のうち4つのカテゴリのみを使用して部分的なデータセットを作成します。

>>> categories = ['alt.atheism', 'soc.religion.christian',
...               'comp.graphics', 'sci.med']

これらのカテゴリに一致するファイルのリストを次のように読み込むことができます:

>>> from sklearn.datasets import fetch_20newsgroups
>>> twenty_train = fetch_20newsgroups(subset='train',
...     categories=categories, shuffle=True, random_state=42)

返されるデータセットは、scikit-learn の "bunch"です。フィールドを持つ単純なホルダーオブジェクトで、利便性のためにPythonの dict キーや object の属性としてアクセスすることができます。たとえば、target_namesには、要求されたカテゴリ名のリストが格納されます。

>>> twenty_train.target_names
['alt.atheism', 'comp.graphics', 'sci.med', 'soc.religion.christian']

ファイル自体は、データ属性のメモリにロードされます。参照のため、ファイル名も利用できます:

>>> len(twenty_train.data)
2257
>>> len(twenty_train.filenames)
2257

では、読み込まれたファイルの最初の行を出力しましょう:

>>> print("\n".join(twenty_train.data[0].split("\n")[:3]))
From: sd345@city.ac.uk (Michael Collier)
Subject: Converting images to HP LaserJet III?
Nntp-Posting-Host: hampton

>>> print(twenty_train.target_names[twenty_train.target[0]])
comp.graphics

教師あり学習アルゴリズムでは、トレーニングセット内の各ドキュメントのカテゴリラベルが必要です。この場合、カテゴリはニュースグループの名前であり、個々の文書を保持するフォルダの名前でもあります。
スピードとスペース効率の理由から、scikit-learnは target_names リスト内のカテゴリ名のインデックスに対応する整数の配列として target 属性をロードします。各サンプルのカテゴリ整数IDは、 target 属性に格納されます。

>>> twenty_train.target[:10]
array([1, 1, 3, 3, 3, 3, 3, 2, 2, 2])

次のようにカテゴリ名を取得することが可能です:

>>> for t in twenty_train.target[:10]:
...     print(twenty_train.target_names[t])
...
comp.graphics
comp.graphics
soc.religion.christian
soc.religion.christian
soc.religion.christian
soc.religion.christian
soc.religion.christian
sci.med
sci.med
sci.med

サンプルがランダムにシャッフルされていることに気付くでしょう(固定乱数シードで)。完全なデータセットをトレーニングする前に、最初のサンプルのみを利用してモデルを素早くトレーニングし、最初のアイデアの結果を試すのに便利です。

テキストファイルからの特徴の抽出

テキスト文書の機械学習を行うためには、まずテキストコンテンツを数値の特徴ベクトルに変換する必要があります。

Bag of Words

これを行う最も直感的な方法は、Bag of Words表現です:

  1. 訓練集合の任意の文書中に存在する各単語に固定整数idを割り当てる(例えば、単語から整数インデックスへの辞書を構築することによって)。
  2. 各文書 #i について、各単語 w の出現回数をカウントし、それを特徴量 #j の値として X[i, j] に格納する。ここで、 j は辞書内の単語 w のインデックスである

Bags of words表現は、n_features がコーパス内の別個の単語の数であることを意味する。この数字は、典型的には100,000を超える。
n_samples == 10000 の場合、Xnumpy の浮動小数点数配列として格納するには、今日のコンピュータでもなかなか苦しい 10000 x 100000 x 4bytes = 4GBのRAM が必要です。
幸運なことに、 Xのほとんどの値は0 になります。これは、指定されたドキュメントでは数千もの異なる単語が使用されるためです。この理由から、Bag of Wordsは 高次元の疎なデータセット であると言えます。特徴ベクトルの非ゼロ部分のみをメモリに記憶することによって、多くのメモリを節約することができる。
scipy.sparse 行列はまさにこれを行うデータ構造であり、scikit-learnはこれらの構造の組み込みサポートを持っています。

scikit-learnでテキストをトークン化する

ストップワードのテキスト前処理、トークン化、およびフィルタリングは、フィーチャの辞書を構築してドキュメントをフィーチャベクターに変換できる上位レベルのコンポーネントに含まれています。

>>> from sklearn.feature_extraction.text import CountVectorizer
>>> count_vect = CountVectorizer()
>>> X_train_counts = count_vect.fit_transform(twenty_train.data)
>>> X_train_counts.shape
(2257, 35788)

CountVectorizer は、N-gram の単語または連続する文字のカウントをサポートします。一旦適合されると、ベクトル化器は特徴指標の辞書を構築します:

>>> count_vect.vocabulary_.get(u'algorithm')
4690

ボキャブラリ内の単語のインデックス値は、トレーニングコーパス全体の頻度にリンクしています。

回数から頻度へ

単語数カウントは良いスタートですが、同じトピックについて話していても、ドキュメントが長いほど平均カウント値が高くなります。
これらの潜在的な不一致を回避するには、ドキュメント内の各単語の出現回数を文書内の単語の総数で除算するだけで十分です。これらの新しい機能は、Term Frequenciesの tf と呼ばれます。
tfの別の改良は、コーパスの多くの文書に出現する単語の重みを小さくすることです。コーパスに稀に出てくる単語よりも有益ではない。
このダウンスケーリングは、「Term Frequency times Inverse Document Frequency」のtf-idfと呼ばれます。
tftf-idf は、次のように計算できます。

>> from sklearn.feature_extraction.text import TfidfTransformer
>>> tf_transformer = TfidfTransformer(use_idf=False).fit(X_train_counts)
>>> X_train_tf = tf_transformer.transform(X_train_counts)
>>> X_train_tf.shape
(2257, 35788)

上記の例のコードでは、最初に fit(...) メソッドを使用して、データに推定値をフィットさせ、次にcount-matrixをtf-idf表現に変換する transform(...) メソッドを使用します。これらの2つのステップを組み合わせて、冗長な処理をスキップすることで、同じ最終結果をより迅速に達成することができます。これは、以下に示すように、前のセクションの注記で説明したように、 fit_transform(..) メソッドを使用して行います。

>>> tfidf_transformer = TfidfTransformer()
>>> X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)
>>> X_train_tfidf.shape
(2257, 35788)

分類器のトレーニング

さて特徴量を手に入れたので、分類器を訓練して、投稿のカテゴリを予測することができます。ナイーブベイズ分類器から始めましょう。これは、このタスクのための素晴らしいベースラインを提供します。 scikit-learnには、この分類器のいくつかの変種が含まれています。単語数に最も適したものは多項式の変形です:

>>> from sklearn.naive_bayes import MultinomialNB
>>> clf = MultinomialNB().fit(X_train_tfidf, twenty_train.target)

新しい文書の結果を予測するには、以前とほぼ同じ特徴抽出チェーンを使用して特徴量を抽出する必要があります。 違いは、すでにトレーニングセットにfitしているので、変換器の fit_transform の代わりに transform を呼び出すことです。

>>> docs_new = ['God is love', 'OpenGL on the GPU is fast']
>>> X_new_counts = count_vect.transform(docs_new)
>>> X_new_tfidf = tfidf_transformer.transform(X_new_counts)

>>> predicted = clf.predict(X_new_tfidf)

>>> for doc, category in zip(docs_new, predicted):
...     print('%r => %s' % (doc, twenty_train.target_names[category]))
...
'God is love' => soc.religion.christian
'OpenGL on the GPU is fast' => comp.graphics

パイプラインの構築

「ベクトル化器 => 変換器 => 分類器」といった一連の処理を使いやすくするために、scikit-learnは、複合分類器のように動作する Pipeline クラスを提供します。

>>> from sklearn.pipeline import Pipeline
>>> text_clf = Pipeline([('vect', CountVectorizer()),
...                      ('tfidf', TfidfTransformer()),
...                      ('clf', MultinomialNB()),
... ])

名前 vecttfidf および clf(分類器の略)は任意です。以下では、グリッド検索のセクションでその使用方法を見ていきます。次のコマンドを使用してモデルを訓練することができます。

>>> text_clf = text_clf.fit(twenty_train.data, twenty_train.target)

テストセットのパフォーマンスの評価

モデルの予測精度を評価することも同様に簡単です。

>>> twenty_test = fetch_20newsgroups(subset='test',
...     categories=categories, shuffle=True, random_state=42)
>>> docs_test = twenty_test.data
>>> predicted = text_clf.predict(docs_test)
>>> np.mean(predicted == twenty_test.target)            
0.834...

私たちは、83.4%の精度を達成しました。(ナイーブベイズよりも少し遅いですが)最良のテキスト分類アルゴリズムの1つと広く認識されている 線形サポートベクターマシン(SVM) でうまくいくかどうかを見てみましょう。異なる分類器オブジェクトをパイプラインに差し込むだけで、学習者を変更できます:

>>> from sklearn.linear_model import SGDClassifier
>>> text_clf = Pipeline([('vect', CountVectorizer()),
...                      ('tfidf', TfidfTransformer()),
...                      ('clf', SGDClassifier(loss='hinge', penalty='l2',
...                                            alpha=1e-3, n_iter=5, random_state=42)),
... ])
>>> _ = text_clf.fit(twenty_train.data, twenty_train.target)
>>> predicted = text_clf.predict(docs_test)
>>> np.mean(predicted == twenty_test.target)            
0.912...

scikit-learnはさらに結果のより詳細なパフォーマンス分析のためのユーティリティを提供します:

>>> from sklearn import metrics
>>> print(metrics.classification_report(twenty_test.target, predicted,
...     target_names=twenty_test.target_names))
...                                         
                        precision    recall  f1-score   support

           alt.atheism       0.95      0.81      0.87       319
         comp.graphics       0.88      0.97      0.92       389
               sci.med       0.94      0.90      0.92       396
soc.religion.christian       0.90      0.95      0.93       398

           avg / total       0.92      0.91      0.91      1502


>>> metrics.confusion_matrix(twenty_test.target, predicted)
array([[258,  11,  15,  35],
       [  4, 379,   3,   3],
       [  5,  33, 355,   3],
       [  5,  10,   4, 379]])

予想通り、混乱のマトリックスは、無神論(atheism) とクリスチャンに関するニュースグループからの投稿が、コンピュータグラフィックスよりも互いにしばしば混同されていることを示しています。

グリッド検索によるパラメータチューニング

TfidfTransformeruse_idf などのパラメータがすでに発生しています。分類器は多くのパラメータも持つ傾向があります。 MultinomialNB には平滑化パラメータ alpha が含まれており、SGDClassifierにはペナルティパラメータalphaと目的関数内に設定可能な損失とペナルティ項があります(モジュールのマニュアルを参照するか、Pythonの help関数を使用してこれらの説明を参照してください)。
チェインのさまざまなコンポーネントのパラメータを微調整する代わりに、可能な値のグリッド上で最良のパラメータを網羅的に検索することができます。idfの有無、線形SVMに対してペナルティパラメータ(alpha)0.01または0.001、ベクタライザの分割方法を、単語またはバイグラムのいずれか、で試行します。

>>> from sklearn.model_selection import GridSearchCV
>>> parameters = {'vect__ngram_range': [(1, 1), (1, 2)],
...               'tfidf__use_idf': (True, False),
...               'clf__alpha': (1e-2, 1e-3),
... }

明らかに、このような徹底的な検索は高価になる可能性があります。複数のCPUコアがあれば、グリッドサーチャーに n_jobs パラメーターを渡して、8つのパラメーターの組み合わせを並行して試してもらうように指示できます。このパラメータに -1 という値を指定すると、インストールされているコアの数が検出され、それらのすべてが使用されます。

>>> gs_clf = GridSearchCV(text_clf, parameters, n_jobs=-1)

グリッド検索インスタンスは、通常のScikit学習モデルのように動作します。トレーニングデータのより小さなサブセットで検索を実行して計算を高速化しましょう:

>>> gs_clf = gs_clf.fit(twenty_train.data[:400], twenty_train.target[:400])

GridSearchCV オブジェクトを fit した結果は、 predict が使用できる分類器です。

>>> twenty_train.target_names[gs_clf.predict(['God is love'])[0]]
'soc.religion.christian'

オブジェクトの best_score_ および best_params_ 属性には、そのスコアに対応する最良平均スコアおよびパラメータ設定が格納されます。

>>> gs_clf.best_score_                                  
0.900...
>>> for param_name in sorted(parameters.keys()):
...     print("%s: %r" % (param_name, gs_clf.best_params_[param_name]))
...
clf__alpha: 0.001
tfidf__use_idf: True
vect__ngram_range: (1, 1)

検索の詳細については、gs_clf.cv_results_ を参照してください。
cv_results_パラメータは、後の検査のために DataFrame としてpandasに簡単にインポートできます。

エクセサイズ

エクセサイズを行うには、 skeletons フォルダの内容を workspace という名前の新しいフォルダとしてコピーします。

% cp -r skeletons workspace

その後、元のエクササイズ指示が失われることなく、ワークスペースの内容を編集することができます。
次に、ipythonシェルを起動し、work-in-progressスクリプトを実行します。

[1] %run workspace/exercise_XX_script.py arg1 arg2 arg3

例外がトリガされた場合、 %debug を使用して検死デバッグセッションを開始します。
実装を改良し、エクセサイズが解決されるまで繰り返します。
各演習では、スケルトンファイルに必要なすべてのインポートステートメント、データを読み込むための定型コード、モデルの予測精度を評価するためのサンプルコードが用意されています。

エクセサイズ1:言語の識別

  • カスタムプリプロセッサと CharNGramAnalyzer を使用して、Wikipediaの記事のデータをトレーニングセットとして使用して、テキスト分類パイプラインを作成します。
  • いくつかのテストセットのパフォーマンスを評価します。

ipythonコマンドライン:

%run workspace/exercise_01_language_train_model.py data/languages/paragraphs/

エクセサイズ2:映画レビューの感情分析

  • ムービーレビューを肯定的または否定的な方法で分類するためのテキスト分類パイプラインを作成します。
  • グリッド検索を使用して、適切なパラメータセットを見つけます。
  • ホールドアウトされたテストセットのパフォーマンスを評価します。

ipythonコマンドライン:

%run workspace/exercise_02_sentiment.py data/movie_reviews/txt_sentoken/

エクセサイズ3:CLIテキスト分類ユーティリティ

  • 前のエクセサイズの結果と標準ライブラリの cPickle モジュールを使用して、stdinから供給されるテキストの言語を検出し、テキストが英語で書かれている場合は極性(正または負)を推定するコマンドラインユーティリティを記述します。
  • ボーナスポイント:ユーティリティがその予測のための信頼水準を与えることができるかどうか。

次は

このチュートリアルを完了したら、 scikit を直感的に理解するのを助けるいくつかの提案があります:


チュートリアル 目次 / 次のチュートリアル

©2010 - 2016、scikit-learn developers(BSDライセンス)。

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10