初心者の特徴エンジニアリング

特徴エンジニアリングに勉強しようと思い，備忘録．  
逐次更新していきたいと考えています!!  

#### この記事の読み方
各項目ごとに， Jupyter-notebookをGitHub上にUpしているので，それを見ながら記事を読んでいただければ幸いです．

# 特徴エンジニアリングとは
Microsoft Azureの定義より，
> 特徴エンジニアリングでは、学習プロセスの促進に役立つ生データから特徴を作成して、学習アルゴリズムの予測力を高めることを試みます。  特徴のエンジニアリングと選択は TDSP の一部です。
> -   **特徴エンジニアリング**:このプロセスは、データに内在している既存の生の特徴から、関連する特徴を作成し、学習アルゴリズムの予測力を高めようとします。
> -   **特徴選択**:このプロセスは、トレーニング問題の次元を削減しようとして、元のデータが持つ特徴のキーのサブセットを選択します。

このようにより精度の高いモデルを構築したり，識別結果をより説明しやすい環境にするための手法です．

# データの説明
今回は，2種類のデータセットを使ってみます．

- [Kuzushiji-MNIST | Kaggle](https://www.kaggle.com/anokas/kuzushiji)
- [Titanic: Machine Learning from Disaster | Kaggle](https://www.kaggle.com/c/titanic)

`Kuzushiji-MNIST` は，日本語の崩し文字をMNISTみたいに文字画像をクラス分類するデータセット  
`Titanic` はkaggleで有名な，タイタニック号の生存者クラス分類問題  

特徴エンジニアリングにおいて，非常に有効な手法であり，`特徴の重要度`を取得できるため，`Titanic`のような意味のある特徴に直感的に理解する上で有効です．(MNISTのような画素レベルの特徴でも有効な手法です!!) 

# Pearson Correlation | ピアソンの相関係数

一般的に統計で使われている `相関係数` です．各特徴と教師ラベルとの相関係数をそれぞれ取り，識別に有意な特徴を選定する手法です．以下のサイトが概念をわかりやすく説明されています．

[「相関係数」ってなんですか？ -意味と利点と欠点をわかりやすく- - Data Science by R and Python](http://tomoshige-n.hatenablog.com/entry/2014/08/06/035001)

## GitHub
House Detecting: [Machine-Learning/Pearson_Correlation.ipynb at master · sasayabaku/Machine-Learning](https://nbviewer.jupyter.org/github/sasayabaku/Machine-Learning/blob/master/PreProcessing/Pearson_Correlation.ipynb)  

## How to
### 相関係数の取得方法
詳しくは，GitHubの `Cal Correlations` にありますが，下図のように特徴ごとに特徴と教師ラベルの線形回帰を行います．  
**(データの分散がすごいので，この回帰は微妙にも見えるが...)**

この4つは今回試したデータの中で相関の高い特徴です．

![plot_regressionline.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152224/b61bca50-7294-a150-5322-dbbdb64ab128.png)


### 相関係数の高いものを取得
GitHubの `Plot Correlation` 辺りです!  
各特徴の相関係数を取得し，高いもの上位10個を取得したものが下図になります．この場合，`0.79` の相関係数である `OverallQual` がラベルと最も相関があると考えられます．

![correlation.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152224/fd4c7bc3-da24-f98d-de42-8d7e41348c08.png)


## 選定した特徴で学習をした際の精度 | 線形回帰
では，特徴選択が終了したので，学習して精度がどうなるかを確認します．  
**特徴全て使った時(289次元)** を用いた時と，**相関の高い特徴10次元**を用いた場合でほとんど精度が変わらないので，**相関による特徴選択が有効**であることが若干表現できている気がします．

![learning_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152224/a1c39325-ce8e-cc44-0853-348cb7d42938.png)


## デメリット
タスクが回帰問題の場合，双方が連続値なので相関係数がカテゴリデータなど離散的な特徴では効果がない場合があります．


# LightGBM
LightGBMは決定木の1つであり，Gradient Boostingと呼ばれるアンサンブル学習を応用して,シンプルながら汎化性能を持つ手法になります．  
[こちらのサイト](https://www.codexa.net/lightgbm-beginner/)の `LightGBMの仕組み` が非常にわかりやすく説明されています!

## GitHub
[Machine-Learning/Titanic_LightGBM.ipynb at master · sasayabaku/Machine-Learning](https://nbviewer.jupyter.org/github/sasayabaku/Machine-Learning/blob/master/Decision_Tree/Titanic_LightGBM.ipynb)

## 環境セットアップ
今回は，Pythonの `lightgbm` ライブラリを使います．

### Install
```py
pip install -y lightgbm
```

### 学習

<details><summary>LightGBMの学習を説明してます | クリックしてください</summary>
<div>

#### 学習パラメータ設定
```py
params = {
    'task': 'train',
    'boosting_type': 'gbdt',
    'objective': 'multiclass',
    'num_class': 2,
    'verbose': 2,
    'seed': seed_value
}
```
`boosting_type`は，[元論文](https://papers.nips.cc/paper/6907-lightgbm-a-highly-efficient-gradient-boosting-decision-tree.pdf)で`Gradient Base`での学習が良いので，それを使います．

#### データをフォーマット変換
`LightGBM`ライブラリは，専用の`Dataset`モジュールに変換する必要があります．

```py
lgbm_train_data = lightgbm.Dataset(train_data, label=train_labels)
lgbm_validation_data = lightgbm.Dataset(validation_data, label=validation_labels, reference=lgbm_train_data)
```

#### 学習
```py
evaluation_results = {}
history = lightgbm.train(
    params, 
    lgbm_train_data,
    valid_sets=[lgbm_train_data, lgbm_validation_data],
    valid_names=['Train', 'Validation'],
    evals_result=evaluation_results,
    feval=accuracy,
    num_boost_round=500,
    verbose_eval=20,
    early_stopping_rounds=50
)
```
`valid_sets`と`valid_names`で対応させることで，ログに学習ログとValidationログが残るように設定(`eval_result`に格納するdict型の変数を用意)．  
`feval`には，評価関数を設定するのですが，分類器なのに`Accuracy`が存在しない・・・ :expressionless: なので，下記のコードで自作します．  
`num_boost_round`は，いわゆる**Epoch数**です．LightGBMは反復学習するので，iterate回数を設定する．`early_stopping_rounds`で一定反復数，評価関数の**best score**が更新されない場合は学習を止めるように設定します(**過学習防止**のため)．

```py
def accuracy(preds, data):
    y_true = data.get_label()
    N_LABELS = 2
    reshaped_preds = preds.reshape(N_LABELS, len(preds) // N_LABELS)
    
    y_pred = np.argmax(reshaped_preds, axis=0)
    acc = np.mean(y_true == y_pred)
    
    return 'accuracy', acc, True
```

</div>
</details>

### 特徴選択
`LightGBM`では`importance`(重要度)が学習パラメータとして入るため，それを用いて，特徴選択を行うテクニックがあります．  
#### 重要度の視覚化
`history`(学習ログ)から，`feature_importance`(重要度)と対応する`feature_name`(特徴名)をDataFrame化し，`importance`の値でソートします．

```py
importances  = pd.DataFrame(
    {'features': history.feature_name(),
     'importance': history.feature_importance()
    }
).sort_values('importance', ascending=False)
importances.reset_index(drop=True)
```

![feature_importance.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152224/bb46f974-c0f2-9bbf-9a29-0e506c7d6585.png)


## LinearSVCで特徴選択の有効性チェック
### Titanic
チューニングなしの`LinearSVC`モデルで精度評価しました．  
特徴をすべて使わずに，**上位6特徴**を用いた場合が平均として精度が良い結果となりました．このようにLightGBMを用いることで`特徴選択`を行うことができ，Kaggleでは`LightGBMをベースライン`にして他のモデルを作成するがあるらしいです．  

![gbm_svm_results.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152224/c70feecf-6c43-7bbf-aba0-73de576f08ad.png)


しかし，下図のようにLightGBMでかなりの精度が出るので，LightGBMがベストモデルであることもしばしば :scream: 

# まとめ
今回は，特徴エンジニアリングとして，  

- ピアソンの相関係数
- LightGBM

による，特徴選択手法を手始めに勉強しました，
今後も逐次的に更新できればと思います．

# 参考文献
1. [LightGBMによるFIFA18の選手データでの市場価値推定 | orizuru](https://orizuru.io/blog/machine-learning/lightgbm-01/)  
1. [Python: LightGBM を使ってみる - CUBE SUGAR CONTAINER](https://blog.amedama.jp/entry/2018/05/01/081842)  
1. [Python: LightGBM でカスタムメトリックを扱う - CUBE SUGAR CONTAINER](https://blog.amedama.jp/entry/lightgbm-custom-metric)  
1. [LightGBM 徹底入門 – LightGBMの使い方や仕組み、XGBoostとの違いについて](https://www.codexa.net/lightgbm-beginner/)