毎日テキストマイニング

180日間、毎日テキストマイニングをするブログです

2018/7/3【13日目】Scikit-learnのチュートリアルを行う。

Tf-idf分析を実装していきたいとおもいます。 0から実装していく力はないので、機械学習ライブラリのScikit-learnを使用していきたいと思います。とはいえ、自分はScikit-learnに触るのは初めてなので、まずは公式のチュートリアルを行いたいと思います。かなりざっくりしてます。

Scikit-learnとは

Scikit-learnはPythonの有名な機械学習ライブラリです。自分でアルゴリズムを実装しなくても、Scikit-learnに投げれば機械学習をしてくれます。今回は下記のチュートリアルをやっていきます。

Working With Text Data Working With Text Data — scikit-learn 0.19.1 documentation

チュートリアルの中では20種類のドキュメントを読み込んで、下記のことを学ぶらしいです。 ファイルのロード 特徴ベクトルを見つける 分類するためのモデルを見つける 特徴と分類の有効な状態を見つける

Scikit-learnのインストール

自分の場合はアナコンダPythonを入れてたはずなので、下記のコマンド。

conda install scikit-learn

それ以外の人はpipでインストールしてください。

pip install -U scikit-learn

インストールできたら、さすがにターミナルでコードを書いていくのはきついので、Jupyter Notebookに移動。

$ jupyter notebook

データセットのロード

Jupyter Notebookに移動したら、今回のチュートリアルで使用するデータセットをロードします。

from sklearn.datasets import fetch_20newsgroups
categories = ['alt.atheism', 'soc.religion.christian', 'comp.graphics', 'sci.med']
twenty_train = fetch_20newsgroups(subset='train', categories=categories, shuffle=True, random_state=42)

f:id:rimt:20180706002528p:plain

これで、データセットがロードできます。categoriesでロードするカテゴリーを限定しているらしいです。 いつロードが終わっているのかタイミングがよくわかりませんが、ロードが完了したかどうかを下記のコマンドで確認してみます。

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

ちゃんと結果が返ってきました。

データセットの中身を見ていく

無事にロードできましたので、データセットの中身を見ていきます。

print("\n".join(twenty_train.data[0].split("\n")[:10]))

0番目にあるデータを10行目まで表示しろというコードです。 実行結果はこんな感じです。

From: sd345@city.ac.uk (Michael Collier)
Subject: Converting images to HP LaserJet III?
Nntp-Posting-Host: hampton
Organization: The City University
Lines: 14

Does anyone know of a good way (standard PC application/PD utility) to
convert tif/img/tga files into LaserJet III format.  We would also like to
do the same, converting to HPGL (HP plotter) files.

機械学習をさせるには、カテゴリー別のデータを用意する必要がり、このデータセットではtarget[に入っているようです。サンプルに沿ってカテゴリーIDを表示してみます。

twenty_train.target[:70]

実行結果。

array([1, 1, 3, 3, 3, 3, 3, 2, 2, 2, 3, 1, 0, 0, 1, 1, 2, 0, 3, 0, 3, 0, 3,
       1, 1, 1, 3, 3, 2, 2, 2, 3, 2, 3, 2, 3, 0, 0, 0, 1, 3, 0, 1, 1, 2, 0,
       3, 3, 1, 2, 1, 2, 0, 0, 2, 1, 2, 3, 0, 1, 0, 3, 1, 2, 1, 1, 2, 0, 3,
       1])

カテゴリーIDが振られた番号が表示されます。どうやらカテゴリーIDは4つしかないようですね。

テキストを分析する前の前処理

テキストを機械学習で分析するには、まずはテキストを数値化する必要があるそうです。 この数値化をするのがBag of Wordsという手法。これは各単語に整数を割り当てて分析しやすくする手法です。Scikit-learnのCountVectorizerというクラスで実装できます。

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)

上から順に覚え書き

  • count_vect = CountVectorizer()

    CountVectorizer()関数を代入。Bag of Wordsで特徴量を作るのに使用。

  • X_train_counts = count_vect.fit_transform(twenty_train.data)

    fit_transformメソッドは行列を対角化しているそうです。(対角化????、後で調べます)

  • X_train_counts.shape

    出力。2257×35788の行列が出力された。

■カテゴリー毎に分析をする 昨日勉強していたtf-idf分析はscikit-learnを使えば簡単に実装できます。

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)

これで終わりで、単語毎に特徴を付けられたそうです。その特徴から、新しい文章がどのカテゴリーに入るのかを分類します。

from sklearn.naive_bayes import MultinomialNB

docs_new = ['this is pen', 'Dayily text mining', 'Happy Hour', 'Visiting Japan']
X_new_counts = count_vect.transform(docs_new)
X_new_tfidf = tfidf_transformer.transform(X_new_counts)
clf = MultinomialNB().fit(X_train_tfidf, twenty_train.target)

predicted = clf.predict(X_new_tfidf)

for doc, category in zip(docs_new, predicted):
    print('%r => %s' % (doc, twenty_train.target_names[category]))

実行結果

'this is pen' => alt.atheism
'Dayily text mining' => soc.religion.christian
'Happy Hour' => soc.religion.christian
'Visiting Japan' => comp.graphics

上から順に覚書。

  • from sklearn.naive_bayes import MultinomialNB

    多項式のナイーブベイズ分類器を使うとの宣言。

  • docs_new = ['this is pen', 'Dayily text mining', 'Happy Hour', 'Visiting Japan']

    新しい言葉を追加。勝手に自分が作りました。

  • X_new_counts = count_vect.transform(docs_new)

    新しく入れた文章をBag of Wordsで整数化。

  • X_new_tfidf = tfidf_transformer.transform(X_new_counts)

    新しく整数化した言葉をtf-idf分析を行う。これでtf-idf分析ができました。試しにX_new_tfidf をprintしてみます。

print(X_new_tfidf)
  (0, 32270) 0.212686048795
  (0, 24748)    0.960792673368
  (0, 18474)    0.177882217916
  (1, 32098)    1.0
  (2, 16897)    0.772575633751
  (2, 16141)    0.634922743438
  (3, 34396)    0.735762763641
  (3, 18662)    0.677239363622

単語が整数化されていますので、どの単語かわからないですが、スコア化されているぽいですね。

  • clf = MultinomialNB().fit(X_train_tfidf, twenty_train.target)

    上の方で作っていたテストデータを学習させる

  • predicted = clf.predict(X_new_tfidf)

    新しく入れた文章を学習したモデルに入れる。predict() メソッドは予測のためのメソッド。

  • for doc, category in zip(docs_new, predicted):

    print('%r => %s' % (doc, twenty_train.target_names[category])) ループで結果の出力をする

パイプライン

今までの流れを簡単にできるようにパイプラインという仕組みがあるらしい。

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

実行結果

Pipeline(memory=None,
     steps=[('vect', CountVectorizer(analyzer='word', binary=False, decode_error='strict',
        dtype=<class 'numpy.int64'>, encoding='utf-8', input='content',
        lowercase=True, max_df=1.0, max_features=None, min_df=1,
        ngram_range=(1, 1), preprocessor=None, stop_words=None,
        strip...inear_tf=False, use_idf=True)), ('clf', MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True))])

今の状態ですと逆にわからないですね。

結果のテスト

scikit-learnを使えばテストも簡単にできるらしいです。こんな感じのコードです。

import numpy as np
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.83488681757656458

この場合テストデータがあって、それと照らし合わしているぽいです。 サンプルを一通り見ただけですが、ひとまず今日はこの辺りで。

今日の結果

今日の呟きは46件でした。内容はこんな感じです。

{'楽しい': 5, '嬉しい': 3, 'すごい': 3, '良い': 2, '可愛い': 2, '早い': 2, 'よろしい': 1, '恥ずかしい': 1, '仲良い': 1, 'あやい': 1, '心強い': 1, 'やばい': 1, 'いい': 1, '悲しい': 1, 'おいしい': 1, '多い': 1, '何気ない': 1, 'おもしろい': 1, '欲しい': 1, '面白い': 1, 'はやい': 1}

'ちゃん': 17, '今日': 12, '公演': 10, 'さん': 10, 'ん': 9, 'たくさん': 8, '初日': 6, '目撃': 6, '者': 6, 'こと': 6, '楽しい': 5, '昨日': 5, '髪型': 5, '写真': 4, 'メンバー': 4, '佐藤': 4, 'チーム': 4, '収録': 4, '詩織': 4, '誰': 4, '嬉しい': 3, 'すごい': 3, 'の': 3, 'お待ち': 3, 'みなさん': 3, '前': 3, '時': 3, '顔': 3, '智代': 3, '梨': 3, '声': 3, '出演': 3, '詩': 3, '私': 3, '本': 3, '目': 3, '人見': 3, '音': 3

'する': 23, 'ちゃん': 17, '今日': 12, '公演': 10, 'さん': 10, 'ん': 9, 'たくさん': 8, 'てる': 7, '初日': 6, '目撃': 6, '者': 6, 'こと': 6, '楽しい': 5, '昨日': 5, '髪型': 5, 'くれる': 5, '見る': 5, 'くださる': 5, 'すぎる': 5, '写真': 4, 'メンバー': 4, '佐藤': 4, 'チーム': 4, '収録': 4, '詩織': 4, '誰': 4, '観る': 4, 'いる': 4, 'いただく': 4, 'ある': 4, 'みる': 4, '嬉しい':

今日勉強したこと

  • scikit-learnを触ってみる
  • sampleを一通り試してみる
  • Bag of Wordsという手法
  • ナイーブベイズ分類器というアルゴリズム