Search on the blog

2015年5月25日月曜日

PandasでCSVを読んでmatplotlibでプロット

 機械学習をするときに、抽出した特徴量の優劣を”見える化”できると便利だよねということでやってみた。

準備
CSVデータを用意する。中身は以下のようなかんじ。

x,label
.....
6.560467,1.000000
6.568159,-1.000000
6.569093,-1.000000
6.588300,-1.000000
6.618156,-1.000000
6.625502,1.000000
6.656761,-1.000000
6.670651,1.000000
6.679807,1.000000
.....

ソースコード
import pandas as pd
import matplotlib.pyplot as plt
 
data = pd.read_csv("/home/kenjih/tmp/train.csv")

print data
 
x1 = data[data['label'] == 1]['x']
x2 = data[data['label'] == -1]['x']
 
plt.hist(x1.as_matrix(), bins=30, histtype='stepfilled', normed=True, color='b', alpha=0.5, label='positive')
plt.hist(x2.as_matrix(), bins=30, histtype='stepfilled', normed=True, color='r', alpha=0.5, label='negative')

plt.xlabel("x")
plt.ylabel("probability")
plt.legend()
plt.show()

結果

2015年5月5日火曜日

scikit-learn(4) Feature selection

 Feature selection(特徴選択)について学習した。

特徴選択とは、識別の前処理において与えられた特徴ベクトルから重要な要素のみを選択する処理のこと[1]。

特徴選択と特徴量抽出は異なることに注意。
特徴選択は与えられた特徴量ベクトルの中から重要な部分空間を取り出す。
これに対して、特徴量抽出は与えられた特徴量から新しい特徴量を作り出す。

特徴選択には以下のような効果がある。
  • 学習時間の短縮化
  • 過学習の軽減による汎化能力の向上
  • モデルの説明力の向上
scikit learnに特徴選択を行う機能が提供されていたので、試してみた。様々な特徴選択アルゴリズムが用意されているが、今回はツリーベースの識別器を使った特徴選択を行った。
from sklearn import datasets
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.cross_validation import train_test_split

data = datasets.load_digits()

X, y = data.data, data.target
X = ExtraTreesClassifier().fit(X, y).transform(X);

trainX, testX, trainY, testY = train_test_split(X, y, test_size=0.4)

clf = ExtraTreesClassifier()

clf.fit(trainX, trainY)
print 'feature size =', trainX.shape[1]
print 'test accuracy =', clf.score(testX, testY)
上記のように、transformメソッドを使うことで特徴選択を行うことが出来る。

次に、特徴選択を行わない場合と行う場合の比較をしてみた。
Dataset「digits」を1000回ずつExtraTreesClassifierで識別した結果を以下に示す。

特徴選択無 特徴選択有
特徴量次元数の平均 64.000 30.419
特徴量次元数の標準偏差 0.000 1.471
特徴量次元数の最小値 64.000 25.000
特徴量次元数の最大値 64.000 35.000
テスト識別率の平均 0.951 0.950
テスト識別率の標準偏差 0.00834 0.00821
テスト識別率の最小値 0.925 0.920
テスト識別率の最大値 0.978 0.972

参考
[1] Feature selection - Wikipedia, the free encyclopedia
[2] 1.13. Feature selection — scikit-learn 0.16.1 documentation

特徴量の重要性

 2,3日前からKaggleのコンテストに参加している。
最近はMachine Learningのライブラリが充実しているので、各アルゴリズムの詳しい知識がなくても識別問題を解くことが出来る。こうなってくると、どのような特徴量を用いるかが重要なファクターになってくると思う。

 機械学習の専門家、Kaggleのトップランカーたちはどのように考えているのか調べてみた[1, 2]のでざっくりとまとめておく。
  • 応用的な機械学習とは、基本的に、素性エンジニアリングである。
  • 問題のドメインについて詳しくなければ、その分野の領域の論文に目を通して既知の重要な特徴量について知る必要がある。
  • 出来るだけたくさんの特徴量を生成して、それから、特徴選択・優先付アルゴリズムを用いて不要な特徴量は削除する。
  • 状況に応じてだが、通常は過少な特徴量よりも過多な特徴量の方がよい。多くのアルゴリズムは何が重要で何が不要かを判断してくれる。
  • データの下調べと素性エンジニアリングが最終的な結果に最も影響を与えるものだ。
やはり特徴量を考察するフェーズは重要だと認識されている。無意味な特徴量を挙げることに不安があったが、これを見る限りだと気にしなくてよさそうだ。

 これを受けて特徴量の考察にかける時間を意識的に増やそうと思う。きちんとスケジュールを立てて、最初の何週までは論文読み、次の何週までは特徴量の考察、...のように。

参考
[1] Feature engineering - Wikipedia, the free encyclopedia
[2] What do top Kaggle competitors focus on?

2015年5月2日土曜日

scikit-learn(3) Random Forest

 Random Forestの勉強をした。自分でも実装できる気がする。まぁ実装しないけど。

Random Forestの概要
  1. 複数個の決定木を用いたアンサンブル学習器
  2. 識別問題のときは最頻値を採用
  3. 回帰問題のときは平均値を採用
  4. ブートストラップサンプリングを行い、各決定木には異なる学習データを入力
  5. 各決定木には特徴量のサブセットを入力
4., 5.により、各決定木の相関性を減らすことができる。
特に、4.では学習データに含まれるノイズの影響を、5.では支配的な特徴量の影響によって木の分割が同様になってしまうことを防ぐ効果がある。
相関性の低い複数個の木の予測値を総合的に評価することで、決定木の弱点である過学習を解決することができる。

scikit-learnサンプル
前回と同じく「digits」の識別を行った。
from sklearn import datasets, metrics
from sklearn.ensemble import RandomForestClassifier
from sklearn.cross_validation import train_test_split

# load data
digits = datasets.load_digits()
X = digits.data
y = digits.target

# split data into (train, test)
trainX, testX, trainY, testY = train_test_split(X, y, test_size=0.2)

# train a classifier
clf = RandomForestClassifier(min_samples_split=1, n_estimators=50, max_features=8)
clf.fit(trainX, trainY)

# predict test data
predictY = clf.predict(testX)
print metrics.classification_report(testY, predictY)
print metrics.confusion_matrix(testY, predictY)
テスト識別率は、98%。
パラメータは適当に選んでいるにも関わらず、よい結果がえられた。 乱数が入っているため結果は決定的ではないが、だいたい96〜98%程度に収まった。
             precision    recall  f1-score   support

          0       1.00      1.00      1.00        29
          1       1.00      1.00      1.00        40
          2       1.00      0.97      0.99        40
          3       0.98      0.93      0.95        45
          4       1.00      0.95      0.97        41
          5       0.97      1.00      0.99        33
          6       1.00      0.97      0.98        33
          7       0.92      1.00      0.96        36
          8       0.91      0.97      0.94        32
          9       1.00      1.00      1.00        31

avg / total       0.98      0.98      0.98       360

[[29  0  0  0  0  0  0  0  0  0]
 [ 0 40  0  0  0  0  0  0  0  0]
 [ 0  0 39  0  0  0  0  0  1  0]
 [ 0  0  0 42  0  1  0  1  1  0]
 [ 0  0  0  0 39  0  0  2  0  0]
 [ 0  0  0  0  0 33  0  0  0  0]
 [ 0  0  0  0  0  0 32  0  1  0]
 [ 0  0  0  0  0  0  0 36  0  0]
 [ 0  0  0  1  0  0  0  0 31  0]
 [ 0  0  0  0  0  0  0  0  0 31]]

2015年5月1日金曜日

scikit-learn(2) SVMのパラメータチューニング

 昨日に引き続き、scikit-learnの勉強。

今回は”手書き数字”を識別するデータセット「digits」にチャレンジした。
このデータセットは「iris」とは異なり、デフォルトパラメータで識別を行なっても良い結果はえられない。

ということでパラメータのチューニングを行わなければならない。
パラメータの候補を渡すとcross validationを行って良いパラメータを選んでくれる関数があったのでそれを使用した。
from sklearn import svm, datasets, grid_search, metrics
from numpy import logspace

# load data
digits = datasets.load_digits()
X = digits.data
Y = digits.target

# split data into (training, test)
train_data_num = 1000
trainX, trainY = X[:train_data_num], Y[:train_data_num]
testX, testY = X[train_data_num:], Y[train_data_num:]

# train SVM
# use cross validation to choose good parameters from grid points
parameters = {
    'C' : logspace(-10, 10, base=2),
    'gamma' : logspace(-10, 10, base=2)
}
 
grsrch = grid_search.GridSearchCV(svm.SVC(), parameters)
grsrch.fit(trainX[:100], trainY[:100])

# get an estimator with the best parameters
clf = grsrch.best_estimator_
clf.fit(trainX, trainY)

# predict test data
predictY = clf.predict(testX)
print metrics.classification_report(testY, predictY)
print metrics.confusion_matrix(testY, predictY)
パラメータCの候補は、2^{-10}, 2^{-9}, 2^{-8}, .... 2^{10}、
パラメータgammaの候補は、2^{-10}, 2^{-9}, 2^{-8}, .... 2^{10}
とした。

まず学習データのうち100個だけを使って、パラメータチューニングを実施した。 その後最良のパラメータを持つSVMをすべての学習データで学習させた。

 結果は、以下のとおり。テストデータの識別率は97%。

             precision    recall  f1-score   support

          0       1.00      0.99      0.99        79
          1       0.99      0.96      0.97        80
          2       0.99      0.99      0.99        77
          3       0.97      0.86      0.91        79
          4       0.99      0.95      0.97        83
          5       0.94      0.99      0.96        82
          6       0.99      0.99      0.99        80
          7       0.95      0.99      0.97        80
          8       0.94      1.00      0.97        76
          9       0.94      0.98      0.96        81

avg / total       0.97      0.97      0.97       797

[[78  0  0  0  1  0  0  0  0  0]
 [ 0 77  1  0  0  0  0  0  1  1]
 [ 0  0 76  1  0  0  0  0  0  0]
 [ 0  0  0 68  0  3  0  4  4  0]
 [ 0  0  0  0 79  0  0  0  0  4]
 [ 0  0  0  0  0 81  1  0  0  0]
 [ 0  1  0  0  0  0 79  0  0  0]
 [ 0  0  0  0  0  1  0 79  0  0]
 [ 0  0  0  0  0  0  0  0 76  0]
 [ 0  0  0  1  0  1  0  0  0 79]]
done.