『Python Machine Learning』Chapter.3をRでやってみた(後編)
の続き。
決定境界を可視化する関数ができたので複数のアルゴリズムの決定境界を比較してみる。
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")
ロジスティック回帰
多項回帰なので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")
サポートベクターマシン
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")
カーネル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")
γを大きくすると絶海の孤島(島が2つあるけど)のような決定境界に。
決定木
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")
ランダムフォレスト
決定木と同じく、分割基準の違いのせいか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")
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")
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で行なう模様。