INPUTしたらOUTPUT!

忘れっぽいんでメモっとく

『Python Machine Learning』Chapter.3をRでやってみた(後編)

estrellita.hatenablog.com

の続き。

決定境界を可視化する関数ができたので複数アルゴリズムの決定境界を比較してみる。

scikit-learnのモジュールとcaretのメソッドは一致しないので単純に比較はできないが以下の組み合わせで行なった。

アルゴリズム scikit-leanのパッケージ scikit-learnのモジュール caretのmethod
パーセプトロン sklearn.linear_model Perceptron mlp
ロジスティック回帰 sklearn.linear_model LogisticRegression multinom
サポートベクターマシン sklearn.svm SVC(kernel='linear') svmLinear
カーネルSVM sklearn.svm SVC(kernel='rbf') svmRadial
決定木 sklearn.tree DecisionTreeClassifier rpart2
ランダムフォレスト sklearn.ensemble RandomForestClassifier rf
k近傍法 sklearn.neighbors KNeighborsClassifier knn


3. プロットデータセットの作成

決定境界のプロット用に学習用データセットと検証用データセットを結合する。

X_combined_std = np.vstack((X_train_std, X_test_std))
y_combined = np.hstack((y_train, y_test))


Rの場合、factorのまま結合するとnumericに変わってしまうのでas.characterで文字にした後に結合し、as.factorで再度factorに戻している。

X_combined     <- rbind(X_train, X_test)
X_combined_std <- rbind(X_train_std, X_test_std)
y_combined     <- as.factor(c(as.character(y_train), as.character(y_test)))
test <- seq(106, 150, 1)


4. 決定境界の可視化

長くなるので原著のPythonコードは割愛。

パーセプトロン

単純パーセプトロンそのものはcaretになさそうだったので代わりにニューラルネットワークmlpでやってみた。割と線形に分離している。

ppn.grid <- expand.grid(size=0)
ppn.fit <- train(y = y_train, 
                 x = X_train_std, 
                 method = "mlp",
                 tuneGrid = ppn.grid)
plot_decision_regions(X_combined_std, y_combined, ppn.fit, test) +
  xlab("Petal Length [standardized]") +
  ylab("Petal Width [standardized]") +
  labs(fill = "Species", shape = "Species")

f:id:tak95:20151201185136p:plain


ロジスティック回帰

多項回帰なのでcaretのmethodはmultinomを指定している。

lr.grid <- expand.grid(decay=1000)
lr.fit <- train(y = y_train, 
                x = X_train_std, 
                method = "multinom",
                tuneGrid = lr.grid)
plot_decision_regions(X_combined_std, y_combined, lr.fit, test) +
  xlab("Petal Length [standardized]") +
  ylab("Petal Width [standardized]") +
  labs(fill = "Species", shape = "Species")

f:id:tak95:20151201185208p:plain

サポートベクターマシン

PythonとRがほぼ同じ結果に。

svm.grid <- expand.grid(C=1.0)
svm.fit <- train(y = y_train, 
                 x = X_train_std, 
                 method = "svmLinear",
                 tuneGrid = svm.grid)
plot_decision_regions(X_combined_std, y_combined, svm.fit, test) +
  xlab("Petal Length [standardized]") +
  ylab("Petal Width [standardized]") +
  labs(fill = "Species", shape = "Species")

f:id:tak95:20151201152747p:plain


カーネルSVM

線形カーネルと比較すると決定境界が若干曲線的になっている。

svm.grid <- expand.grid(sigma=0.10, C=1.0)
svm.fit <- train(y = y_train, 
                 x = X_train_std, 
                 method = "svmRadial",
                 tuneGrid = svm.grid)
plot_decision_regions(X_combined_std, y_combined, svm.fit, test) +
  xlab("Petal Length [standardized]") +
  ylab("Petal Width [standardized]") +
  labs(fill = "Species", shape = "Species")

f:id:tak95:20151130204909p:plain


γを大きくすると絶海の孤島(島が2つあるけど)のような決定境界に。

f:id:tak95:20151130204918p:plain


決定木

scikit-learnのDecisionTreeClassifierはエントロピーで分割するがrpart2で使用するCARTはジニ係数で分割する。その違いのせいか決定境界も異なったものになった。

tree.grid <- expand.grid(maxdepth=3)
tree.fit <- train(y = y_train, 
                  x = X_train, 
                  method = "rpart2",
                  tuneGrid = tree.grid)
plot_decision_regions(X_combined, y_combined, tree.fit, test) +
  xlab("Petal Length [cm]") +
  ylab("Petal Width [cm]") +
  labs(fill = "Species", shape = "Species")

f:id:tak95:20151130203445p:plain

ランダムフォレスト

決定木と同じく、分割基準の違いのせいかPythonとRで異なる決定境界になった。

set.seed(0)
rf.grid <- expand.grid(ntree=10, mtry=2)
rf.fit  <- train(y = y_train, 
                  x = X_train, 
                  method = "rf",
                  tuneGrid = rf.grid)
plot_decision_regions(X_combined, y_combined, rf.fit, test) +
  xlab("Petal Length [cm]") +
  ylab("Petal Width [cm]") +
  labs(fill = "Species", shape = "Species")

f:id:tak95:20151130203519p:plain

k近傍法

若干ざらついているがほぼPythonと同じ結果になった。

set.seed(71)
knn.grid <- expand.grid(k=5)
knn.fit  <- train(y = y_train, 
                 x = X_train_std, 
                 method = "knn",
                 tuneGrid = knn.grid)
plot_decision_regions(X_combined_std, y_combined, knn.fit, test) +
  xlab("Petal Length [cm]") +
  ylab("Petal Width [cm]") +
  labs(fill = "Species", shape = "Species")

f:id:tak95:20151130204257p:plain


5. モデルの検証

原著ではテストデータセットの誤分類数、精度を以下のように算出している。

y_pred = ppn.predict(X_test_std)
print('Misclassified samples: %d' % (y_test != y_pred).sum())
from sklearn.metrics import accuracy_score
print('Accuracy: %.2f' % accuracy_score(y_test, y_pred))


Rの場合、caret::postResample()でAccuracyの他にKappa係数なるものも算出してくれる。

> ppn.pred <- predict(ppn.fit, X_test_std)
> postResample(ppn.pred, y_test)
 Accuracy     Kappa 
0.9555556 0.9333333 


より詳細なモデル評価についてはChapter.6で行なう模様。