Edited at

scikit-learnのtutorialをやってみた(Working With Text Data: Exercise 2)

More than 1 year has passed since last update.

Exercise 1に引き続き2もやったのでメモ書きしておきます。


環境


  • macOS High Sierra(10.13.4)

  • Python 3.5.2



資料


内容

今回の課題では映画のレビュー結果を学習し、ポジティブな意見かネガティブな意見かを判定するモデルを作成します。grid-searchを使い、unigramとbigramの比較も行います。前回同様exercise_02_sentiment.pyの空所を埋めていきます。


TASK: Build a vectorizer / classifier pipeline that filters out tokens that are too rare or too frequent

データの前処理、特徴量の抽出、学習を一度に実行するためのpiplelineのインスタンスを作成します。


exercise_02_sentiment.py

from sklearn.feature_extraction.text import TfidfTransformer

# Pipelineのインスタンスを作成
text_clf=Pipeline([
('vect',TfidfVectorizer(max_df=0.99, min_df=0.01)),
('tfidf',TfidfTransformer()),
('clf', LinearSVC())])

min_dfでほとんど出てこない特徴量、max_dfで逆に多すぎる特徴量のフィルタリングをおこなっています。決め打ちでmin_dfを0.01、max_dfを0.99にしました。


TASK: Build a grid search to find out whether unigrams or bigrams are more useful.

grid-searchを実行するインスタンスを作成します。コードは以下です。


exercise_02_sentiment.py

# GridSearchCVのインスタンスを作成

parameters={'vect__ngram_range':[(1,1),(2,2)]}
gs_clf=GridSearchCV(text_clf, parameters, n_jobs=-1, cv=5, verbose=1)

parametersという変数にgrid_searchで検証するパラメータのリストを設定しています。今回の課題ではunigramかbigramの比較をするので、ngram_rangeに(1, 1), (2 , 2)の二つのパラメータを指定しています。cvはN-folds cross validationのNを決めるパラメータです。上記なら5-folds cross validationになります。verboseはgrid-search実行時の出力内容を制御するパラメータで、1にしておくと実行時間等が見れて良い感じです。


TASK: print the cross-validated scores for the each parameters set explored by the grid search

作成したgrid-searchのインスタンスを使ってパラメータの検証を行います。


exercise_02_sentiment.py

# grid-searchを実行

gs_clf=gs_clf.fit(docs_train, y_train)

# 得られたパラメータを表示
print(gs_clf.best_score_)
for param_name in sorted(parameters.keys()):
print("%s: %r" % (param_name, gs_clf.best_params_[param_name]))



TASK: Predict the outcome on the testing set and store it in a variable named y_predicted

grid-searchで得られたパラメータを使ってモデルを学習し直し、テストデータでモデルを検証します。


exercise_02_sentiment.py

# モデルの再構築

text_clf=Pipeline([
('vect',TfidfVectorizer(max_df=0.99, min_df=0.01,
ngram_range=gs_clf.best_params_['vect__ngram_range'])),
('tfidf',TfidfTransformer()),
('clf', LinearSVC())])
# モデルの学習
text_clf.fit(docs_train, y_train)
# テストデータで検証
y_predicted=text_clf.predict(docs_test)

gs_clf(GridSearchCVのインスタンス)のbest_params_にgrid-searchの結果得られた最良のパラメータがdictとして格納されているので、パラメータ名をkeyにして取り出してngram_rangeに設定します。


実行結果

まずはunigramとbigramの比較結果です。unigramが選ばれています。


MBP:TEST_scikit-learn user$ ipython
Python 3.5.2 (default, Sep 10 2016, 22:20:29)
(snip)
In [1]: %run exercise_02_sentiment.py text_analytics/data/movie_reviews/txt_sentoken/
n_samples: 2000
Fitting 5 folds for each of 2 candidates, totalling 10 fits
[Parallel(n_jobs=-1)]: Done 10 out of 10 | elapsed: 15.1s finished
0.827333333333
vect__ngram_range: (1, 1)
precision recall f1-score support

neg 0.86 0.81 0.83 252
pos 0.82 0.86 0.84 248

avg / total 0.84 0.84 0.84 500

[[204 48]
[ 34 214]]



せっかくなので他のパラメータについてもgrid-searchをかけてみました。変更した箇所は以下です。


exercise_02_sentiment.py

# TASK: Build a vectorizer / classifier pipeline that filters out tokens that are too rare or too frequent

text_clf=Pipeline([
('vect',TfidfVectorizer()),
('tfidf',TfidfTransformer()),
('clf', LinearSVC())])
# TASK: Build a grid search to find out whether unigrams or bigrams are more useful.
parameters={'vect__min_df': [0.0, 1],
'vect__max_df': [0.1, 1.0],
'vect__ngram_range': [(1,1) ,(1, 2),
(2,2)], 'clf__C':[0.5, 1.0]}

# TASK: Predict the outcome on the testing set and store it in a variable named y_predicted
text_clf=Pipeline([
('vect',TfidfVectorizer(
max_df=gs_clf.best_params_['vect__max_df'],
min_df=gs_clf.best_params_['vect__min_df'],
ngram_range=gs_clf.best_params_['vect__ngram_range'])),
('tfidf',TfidfTransformer()),
('clf', LinearSVC(C=gs_clf.best_params_['clf__C']))])


結果は以下です。


n_samples: 2000
Fitting 5 folds for each of 24 candidates, totalling 120 fits
[Parallel(n_jobs=-1)]: Done 42 tasks | elapsed: 1.7min
[Parallel(n_jobs=-1)]: Done 120 out of 120 | elapsed: 4.9min finished
0.822666666667
clf_C: 1.0
vectmax_df: 1.0
vectmin_df: 0.0
vect_ngram_range: (1, 2)
precision recall f1-score support

neg 0.86 0.80 0.83 254
pos 0.81 0.86 0.83 246

avg / total 0.83 0.83 0.83 500

[[204 50]
[ 34 212]]



ngram_rangeが(1,2)の場合、unigramとbigramのmixになります。結局bigramの方が微妙に良いという結果に。


おまけ

max_df等を調整せずに特徴量をbigramにしたモデルが一番精度が良かった。


n_samples: 2000
precision recall f1-score support

neg 0.86 0.82 0.84 248
pos 0.83 0.87 0.85 252

avg / total 0.85 0.85 0.85 500

[[204 44]
[ 32 220]]


まとめ

bigramの方が良いだろうと予想していたのですがこれくらいだと誤差の範囲なんでしょうか、この辺りがよくわからないです。scikit-learnの使い方に少し慣れてきたので、手法やモデルの知識もつけて扱えるようになりたいです。


次の課題

そのうち