機械学習ライブラリ scikit-learnの便利機能の紹介

# 概要
Pythonの機械学習系ライブラリscikit-learnの基本的な使い方と、便利だなと思ったものを記載しました。

類似記事は沢山ありますが、自分自身の整理のためにもまとめてみました。
これから、scikit-learnを利用する人にとって、役立つ記事になったら嬉しいです。

# 準備
1. Pythonインストール ： [Windows](http://qiita.com/taiponrock/items/f574dd2cddf8851fb02c)
/ [Mac](https://qiita.com/7110/items/1aa5968022373e99ae28)
2. scikit-learnインストール

```bash
pip install scikit-learn
```


# 公式サイト
http://scikit-learn.org/stable/

# 基本的なモデルクラスの使い方
1. モデルインスタンス生成
2. fitさせる (学習)
3. predictする (予測)

scikit-learnはAPIが統一されていて、とてもわかりやすいです。

## SVMの例

* import文

```py3:svm.py
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
import numpy as np
import pandas as pd
```

* データセットを適当に作成

```py3:svm.py
# class: 0
df_a = pd.DataFrame({'x1': np.random.randn(100),
                     'x2': np.random.randn(100),
                     'y' : 0})
# class: 1
df_b = pd.DataFrame({'x1': np.random.randn(100) + 5,
                     'x2': np.random.randn(100) + 3,
                     'y' : 1})
df = df_a.append(df_b)

# トレーニングデータとテストデータに分割
X_train, X_test, y_train, y_test = \
    train_test_split(df[['x1','x2']], df['y'], test_size=0.2)
```

* モデルクラスを利用した学習と予測

```py3:svm.py
# 1. モデルインスタンス生成
clf = SVC()

# 2. fit 学習
clf.fit(X_train, y_train)

# 3. predict 予測
y_pred = clf.predict(X_test)
```

SVMによる予測結果が`y_pred`に格納されます。


![SVM.png](https://qiita-image-store.s3.amazonaws.com/0/105335/b7370836-4e57-3e58-7f14-19599f4cbb6d.png)

回帰も分類も生成するモデルのクラスを変えるだけで、様々なモデルを簡単に構築できます。 

# 便利機能
## ダミー変数変換
### LabelEncoder と OneHotEncoder
LabelEncoder  : 文字を数値に変換
OneHotEncoder  :　数値をダミー変数に変換

合わせると、カテゴリカル変数をダミー変数に置き換えることができる。

```py3:class_report.py
from sklearn.preprocessing import OneHotEncoder, LabelEncoder

le = LabelEncoder()
oe = OneHotEncoder()
en = le.fit_transform(['orange','orange','apple','banana','apple'])
print(oe.fit_transform(en.reshape(-1, 1)).toarray())
```

![dummy.png](https://qiita-image-store.s3.amazonaws.com/0/105335/4b5c3d87-4275-110a-42bf-440f9932fccd.png)

イメージ
![dummy_image.png](https://qiita-image-store.s3.amazonaws.com/0/105335/ebf00b5f-05a2-da02-dbd4-6f21f3710ce8.png)


**※次のバージョン(v0.20)でCategoricalEncoderが追加されるようです！**
[CategoricalEncoder](http://scikit-learn.org/dev/modules/generated/sklearn.preprocessing.CategoricalEncoder.html)

## データ分割
### train_test_split
学習用データとテストデータを分けるため、データセットをランダムに分割する。

```py3:data_split.py
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = \
       train_test_split(X, y, test_size=0.2, random_state=0)
```


## 交差検証(CV)
### cross_val_score
k分割交差検証法の結果を出力。

```py3:cross_val.py
from sklearn.model_selection import cross_val_score

clf = LogisticRegression()

# 5等分の交差検証
print(cross_val_score(clf, X, y, cv=5))
```

```py3:
>> array([ 0.96551724,  0.93103448,  0.96428571,  0.89285714,  0.92857143])
```

イメージ

![cv_image.png](https://qiita-image-store.s3.amazonaws.com/0/105335/9b313dc4-6472-5e1e-96a6-49900aa526a9.png)

## ハイパーパラメータ選択
### GridSearchCV
グリッドサーチと交差検証を同時に行う。

探索したいハイパーパラメータをdict形式で定義し、GridSearchCVの引数として渡す。
GridSearchCVのfitは、交差検証で最も良いスコアとなるハイパーパラメータで学習してくれる。
便利すぎでしょ!!

```py3:grid_cv.py
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier

# 探索したハイパーパラメータ
param_grid = {'n_estimators': [2, 5, 10],
              'max_depth': [2, 5]}

grid_search = GridSearchCV(RandomForestClassifier(random_state=0), param_grid, cv=5)

# 最適なパラメータで学習
grid_search.fit(X_train, y_train)

print('test_score : {}'.format(grid_search.score(X_test, y_test)))
print('best_params : {}'.format(grid_search.best_params_))

# 各パラメータのCV平均スコア
display(display(pd.DataFrame(grid_search.cv_results_)\
       [['param_max_depth', 'param_n_estimators', 'mean_train_score']]))
```

結果

```py3:
>> test_score : 0.9444444444444444
>> best_params : {'max_depth': 5, 'n_estimators': 10}
```

![gridcv_pd.png](https://qiita-image-store.s3.amazonaws.com/0/105335/f9c506a3-fec7-5697-1d5c-190cd06b2582.png)

イメージ
![gridcv_image.png](https://qiita-image-store.s3.amazonaws.com/0/105335/07a39de6-3b91-34f2-85f7-ea75dafe2233.png)


## パイプライン
### Pipeline
一連の処理ステップをEstimatorとしてまとめることができる。
① 標準化 → ② 次元削減 → ③ ランダムフォレストで学習
の流れを、グリッドサーチ＋CVで検証する場合の例を記載。

グリッドサーチの探索パラメータはPipelineで指定した任意の文字列に”__”(アンダースコア2つ)を付けて指定。

Pipelineで指定できるEstimatorは最後のもの以外はtransformメソッドが定義されている必要がある。

```py3:pipe_line.py
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA

# パイプライン生成
pipe = Pipeline([('scaler', StandardScaler()),
                 ('pca', PCA()),
                 ('rf', RandomForestClassifier(random_state=0))])

# グリッドサーチ用の探索ハイパーパラメータ設定
param_grid = {
    'pca__n_components': [2, 3, 4],
    'rf__n_estimators' : [2, 10, 100],
    'rf__max_depth' : [10, 100, 1000]
}

grid_search = GridSearchCV(pipe, param_grid , cv=5)
grid_search.fit(X_train, y_train)

print('test_score : {}'.format(grid_search.score(X_test, y_test)))
print('best_params : {}'.format(grid_search.best_params_))
```

結果

```py3:
>> test_score : 0.9722222222222222
>> best_params : {'pca__n_components': 2, 'rf__max_depth': 10, 'rf__n_estimators': 10}
```
(標準化+PCAがランダムフォレストに適するかはスルーで)

### make_pipeline
各ステップに明示的に名前をつけなくても、自動でクラス名の小文字によって名前を付けてくれる。

```py3:make_pipeline.py
from sklearn.pipeline import make_pipeline

pipe = make_pipeline(StandardScaler(), PCA(), RandomForestClassifier(random_state=0))

param_grid = {
    'pca__n_components': [2, 3, 4],
    'randomforestclassifier__n_estimators' : [2, 10, 100],
    'randomforestclassifier__max_depth' : [10, 100, 1000]
}
```

## 特徴量選択
### SelectKBest
特徴量をk個に絞る。

* 分類 ( score_func=f_classif ) は[ANOVA](http://www.shiga-med.ac.jp/~koyama/stat/com-anova.html)によって、関連が高い特徴量を選択している。

* 回帰 ( score_func=f_regression ) は相関係数によって、関連が高い特徴量を選択している。

```py3:
from sklearn.feature_selection import SelectKBest, f_regression

sb= SelectKBest(score_func=f_regression, k=10) 
sb.fit(X, y)
X_sb = sb.transform(X)
```


### SelectPercentile
特徴量を割合で指定して絞る。

```py3:
from sklearn.feature_selection import SelectPercentile

sp = SelectPercentile(percentile=50)
sp.fit(X, y)
X_sp = sp.transform(X)
```

## 評価(分類) 
### classification_report
分類問題の評価基準であるprecision(適合率)、recall(再現率)、f1-score(F値)、support(実際のサンプル数)を出力。

```py3:class_report.py
from sklearn.metrics import classification_report

classification_report(y_true, y_pred)
```
![class_report.png](https://qiita-image-store.s3.amazonaws.com/0/105335/1af556c8-e0a7-47c7-111c-198769ee5368.png)

### confusion_matrix
混同行列を出力

```py3:confusion_matrix.py
from sklearn.metrics import confusion_matrix

print(confusion_matrix(y_test, y_pred))
```
![confusion_matrix.png](https://qiita-image-store.s3.amazonaws.com/0/105335/aa105312-05e6-1331-105b-5ec45baa0ff3.png)

イメージ
![confusion_matrix_image.png](https://qiita-image-store.s3.amazonaws.com/0/105335/990ebf6b-fe9b-e500-6662-5b58e6ef0a9f.png)


## 評価(回帰) 
### mean_squared_error
平均二乗誤差を出力。

```math
MSE = \frac{1}{n} \ \sum_{i=1}^{n} (f_{i}-y_{i})^2 \\
```

```py3:mse.py
from sklearn.metrics import mean_squared_error

# RMSE
np.sqrt(mean_squared_error(y_test, y_pred))
```

```py3:
>> 0.62519679744672363
```

## 文章のTF-IDFベクトル変換
### Tfidfvectorizer
文章内における単語の重要度を数値化するTF-IDF法の結果を出力。

```py3:tf-idf.py
from sklearn.feature_extraction.text import TfidfVectorizer

tf_idf = TfidfVectorizer()
X = tf_idf.fit_transform(['Hello mom.',
                          'I am tired.',
                          'I am lazy.',])
print(X.toarray())
```

結果

```py3:
[[ 0.          0.70710678  0.          0.70710678  0.        ]
 [ 0.60534851  0.          0.          0.          0.79596054]
 [ 0.60534851  0.          0.79596054  0.          0.        ]]
```

## データセット
データセットがついている。
とりあえず、何かデータセットが必要な時に便利。

| API       | 説明　　　　| 　|
|:-----------------|:--------------------------|:------------------:|
| load_boston　　| 米国ボストン市郊外における地域別の住宅価格  | 回帰 |
| load_iris　　　| 3 種類の品種のアヤメのがく片、花弁の幅および長さ　| 分類 |
| load_diabetes　　　| 糖尿病患者の検査数値と1年後の疾患進行状況　| 回帰 |
| load_digits　　　| 0~9の手書き文字の8×8画像　| 分類 |
| load_linnerud　　　| 成人男性の生理学的特徴と運動能力 | 回帰 |
| load_wine　　　| 3種類のワインの科学的特徴　| 分類 |　
| load_breast_cancer　　　| 乳がんの診断結果 | 分類 |


データの取得

```py3:
from sklearn.datasets import load_wine

# ワインデータ取得
data, target = load_wine(return_X_y=True)
```
# おわり
誤った記載がありましたら、ご指摘いただけたら嬉しいです。
まだまだ、sklearn使いこなせてないので、ガシガシ使っていきたいです！