深い森(multi-Grained Cascade Forest)の苦手なデータを検証してみる。


# はじめに

## 背景
gcForest(multi-Grained Cascade Forest)の精度は画像認識や、感情分析、音楽分類、手の動きの分類などにおいて、一部の深層学習モデルとRandom Forestsの精度よりも高いことが知られている。
## 内容
本ページでは次のような決定木ベースの機械学習モデルを構築する。

- Random Forests
- gcForest

大規模なアンケートデータを想定し、Random Forestsの精度がgcForestの精度よりも高いことを示す。つまり、gcForestの苦手な部分を検証してみる。


## 学銃的な背景とインストール方法
前回の[深い森(multi-Grained Cascade Forest)と浅い森(Random Forests)を動かして比較してみた](https://qiita.com/KROYO/items/651bae27feae3e938cf2)を参照してください。



```python
import numpy as np
import pandas as pd
import random
import uuid

from sklearn.datasets import make_classification
from sklearn.model_selection import StratifiedKFold, cross_validate
from sklearn.metrics import accuracy_score, cohen_kappa_score, balanced_accuracy_score, make_scorer, f1_score, recall_score

from sklearn.datasets import fetch_mldata
from sklearn.ensemble import ExtraTreesClassifier, RandomForestClassifier
from sklearn.metrics import accuracy_score, f1_score
from sklearn.model_selection import train_test_split

from deep_forest import MGCForest

```

# 実験
## テスト用のデータ作成
### パラメータの値
- n_samples: サンプルの数
    - アンケート調査であれば回答者数に該当
- n_features: 特徴量の数
    - 分類対象(クラス)を識別するために利用する特徴量の数
    - 例えば、アンケート調査であれば質問と回答のペア
- n_informative:分類対象と関係のある特徴量の数
    - この数が多ければ多いほど予測が簡単になる
- n_classes: 分類対象が何種類あるか
    - 2値分類問題にするならば 2 をセット
- random_state: ランダムシードの設定


```python
data = make_classification(n_samples=1000, #生成するサンプル数 
                           n_features=110,  
                           n_informative=100,
                           weights=[0.5,0.5],
                           n_classes=2,
                          random_state=43)
data_set = data[0] # 特徴量
target_set = data[1] # クラスラベル
#from sklearn.datasets import load_iris
#iris = load_iris()
#data_set = iris.data
#target_set =iris.target
```

## gcforestの構築


```python
mgc_forest = MGCForest(
    estimators_config={
        'mgs': [{
            'estimator_class': ExtraTreesClassifier,
            'estimator_params': {
                'n_estimators': 30,
                'min_samples_split': 21,
                'n_jobs': -1,
            }
        }, {
            'estimator_class': RandomForestClassifier,
            'estimator_params': {
                'n_estimators': 30,
                'min_samples_split': 21,
                'n_jobs': -1,
            }
        }],
        'cascade': [{
            'estimator_class': ExtraTreesClassifier,
            'estimator_params': {
                'n_estimators': 1000,
                'min_samples_split': 11,
                'max_features': 1,
                'n_jobs': -1,
            }
        }, {
            'estimator_class': ExtraTreesClassifier,
            'estimator_params': {
                'n_estimators': 1000,
                'min_samples_split': 11,
                'max_features': 'sqrt',
                'n_jobs': -1,
            }
        }, {
            'estimator_class': RandomForestClassifier,
            'estimator_params': {
                'n_estimators': 1000,
                'min_samples_split': 11,
                'max_features': 1,
                'n_jobs': -1,
            }
        }, {
            'estimator_class': RandomForestClassifier,
            'estimator_params': {
                'n_estimators': 1000,
                'min_samples_split': 11,
                'max_features': 'sqrt',
                'n_jobs': -1,
            }
        }]
    },
    stride_ratios=[1.0 / 4, 1.0 / 9, 1.0 / 16],
)
```


```python
%%time
skf = StratifiedKFold(n_splits=5,
                      shuffle=True,
                      random_state=0)
r_data = {}
steps = 1
for train_index, test_index in skf.split(data_set, target_set):
    mgc_forest.fit(data_set[train_index,],target_set[train_index])
    target_pred = mgc_forest.predict(data_set[test_index,])
    r_data[steps] = {'test_accuracy': accuracy_score(target_set[test_index], target_pred),
            'test_kappa':  cohen_kappa_score(target_set[test_index], target_pred),
            'test_blanced_accuracy': balanced_accuracy_score(target_set[test_index], target_pred),
            'test_F1 score': f1_score(target_set[test_index], target_pred, average='weighted')
                     }
    steps +=1

```


    CPU times: user 13min 1s, sys: 27.4 s, total: 13min 28s
    Wall time: 12min 37s



```python
## Random forests の構築
```


```python
model = RandomForestClassifier(random_state = 43,
                               n_jobs = -1,
                               n_estimators = 1000,
                               max_features = 'log2',
                               max_depth = None, 
                               oob_score=False)
```


```python
%%time
skf = StratifiedKFold(n_splits=5,
                      shuffle=True,
                      random_state=0)
rf_data = {}
steps = 1
for train_index, test_index in skf.split(data_set, target_set):
    #print("分割されたデータセットの大きさ:{}".format(target_set[test_index].shape))
    #print("分割される以前のデータセットのどこを抽出したのか？:{}".format(test_index))
    #print("クラスラベル:{}".format(target_set[test_index]))
    #print("クラスラベルの種類別個数{}".format( np.unique(target_set[test_index],return_counts=True)))
    model.fit(data_set[train_index,],target_set[train_index])
    target_pred = model.predict(data_set[test_index,])
    rf_data[steps] = {'test_accuracy': accuracy_score(target_set[test_index], target_pred),
            'test_kappa':  cohen_kappa_score(target_set[test_index], target_pred),
            'test_blanced_accuracy': balanced_accuracy_score(target_set[test_index], target_pred),
            'test_F1 score': f1_score(target_set[test_index], target_pred, average='weighted')
                     }
    steps +=1


```

    CPU times: user 17.2 s, sys: 1.64 s, total: 18.9 s
    Wall time: 8.61 s


# 結果
## gcforestの精度


```python
r_data
```




    {1: {'test_accuracy': 0.582089552238806,
      'test_kappa': 0.16357871792331324,
      'test_blanced_accuracy': 0.5817326732673267,
      'test_F1 score': 0.5799051338290626},
     2: {'test_accuracy': 0.6119402985074627,
      'test_kappa': 0.22363078142022386,
      'test_blanced_accuracy': 0.6117821782178218,
      'test_F1 score': 0.6115363902138791},
     3: {'test_accuracy': 0.675,
      'test_kappa': 0.35,
      'test_blanced_accuracy': 0.675,
      'test_F1 score': 0.6736210489317367},
     4: {'test_accuracy': 0.6030150753768844,
      'test_kappa': 0.20629070530620486,
      'test_blanced_accuracy': 0.6031818181818182,
      'test_F1 score': 0.6025936582952676},
     5: {'test_accuracy': 0.6080402010050251,
      'test_kappa': 0.21566447700859026,
      'test_blanced_accuracy': 0.6077777777777778,
      'test_F1 score': 0.6069481144323441}}



## Random Forestsの精度


```python
rf_data
```




    {1: {'test_accuracy': 0.8507462686567164,
      'test_kappa': 0.7014851485148514,
      'test_blanced_accuracy': 0.8507425742574257,
      'test_F1 score': 0.8507462686567164},
     2: {'test_accuracy': 0.8159203980099502,
      'test_kappa': 0.6317405298341173,
      'test_blanced_accuracy': 0.8157920792079207,
      'test_F1 score': 0.8157835867115555},
     3: {'test_accuracy': 0.865,
      'test_kappa': 0.73,
      'test_blanced_accuracy': 0.865,
      'test_F1 score': 0.8647260702923422},
     4: {'test_accuracy': 0.8391959798994975,
      'test_kappa': 0.6783838383838383,
      'test_blanced_accuracy': 0.8391919191919192,
      'test_F1 score': 0.8391959798994975},
     5: {'test_accuracy': 0.8090452261306532,
      'test_kappa': 0.6181579478893153,
      'test_blanced_accuracy': 0.8091414141414142,
      'test_F1 score': 0.8089873493553846}}



# まとめ

- 小規模データセット(1000人, 110種類の質問)の精度
    - Random Forestsの精度がgcForestよりも優れていた。
- 計算時間
    - gcforest: 12min 37s
    - Random Forests: 8.61 s

以上から、データに合わせて手法を選ぶべき、ということがわかる。

- 想像
    - 訓練データへの精度は全て1.0であるため、データが少ないにも関わらず学習しすぎていることが、原因か？