Azure Machine Learning スタジオで、Kaggleデータセットで機械学習を試すq

# Azure Machine Learning スタジオで、Kaggleデータセットで機械学習を試す。

こんにちは。 
今回は、[Azure Machine Learning スタジオ](https://docs.microsoft.com/ja-jp/azure/machine-learning/overview-what-is-machine-learning-studio)に、[kaggle](https://www.kaggle.com/)の有名なクレジットカード不正検知のデータセットを使って機械学習環境を試す手順を紹介します。
この手順は、むかしに[Azure Synapse Analytics](https://docs.microsoft.com/ja-jp/azure/synapse-analytics/overview-what-is)を使い倒すために、[Transact-SQL](https://docs.microsoft.com/ja-jp/sql/t-sql/language-reference?view=sql-server-ver15)から直接[ONNXモデル](https://docs.microsoft.com/ja-jp/windows/ai/windows-ml/get-onnx-model)を呼び出して、タイムリーな推論をSQL文だけで実現するための検証を行うために、簡単な機械学習モデル作成用に準備した簡易的なnotebookとTerraformのコードになっています。

## 本記事を実施する上での要件

ローカルマシンに導入が必要なソフトウェア
> - tfenv：2.2.2
> - terraform：0.15.4
> - azure-cli：2.23.0

## 前提条件
本記事ではサンプルコードとしてTerraformとPythonのソースコードを使用します。  [Azure Machine Learning スタジオ](https://docs.microsoft.com/ja-jp/azure/machine-learning/overview-what-is-machine-learning-studio) の環境構築はローカルマシンよりTerraformで行うため、AzureCLIとTerraformの実行環境が必要になります。サンプルコードの実行には、Azureサブスクリプションが必要になります。
サブスクリプションによっては[クォーター制限](https://docs.microsoft.com/ja-jp/azure/machine-learning/how-to-manage-quotas) が生じる可能性があります。その場合はサブスクリプション管理者か公式サポートへ問い合わせをお願いします。機械学習のモデルの学習と評価を [Azure Machine Learning スタジオ](https://docs.microsoft.com/ja-jp/azure/machine-learning/overview-what-is-machine-learning-studio)で行います。
リソースを上手に取り扱いする事で、無償の範囲内でも試せるようですので、課金額に注意した上で試してみてください。

## 目次
- [事前準備](#事前準備)
    - [Kaggleのアカウントの準備](#Kaggleのアカウントの準備)
    - [使用するデータセットのダウンロード](#使用するデータセットのダウンロード)
    - [Azure環境の準備](#Azure環境の準備)
    - [コンピューティングの作成](#コンピューティングの作成)
    - [分析に必要な追加モジュールのインストール](#分析に必要な追加モジュールのインストール)
- [データの分析](#データの分析) 
    - [使用するデータセットについて](#使用するデータセットについて)
    - [新しいNotebookの作成](#新しいNotebookの作成)
    - [使用するライブラリの宣言](#使用するライブラリの宣言)
    - [データを視覚化](#データを視覚化)
    - [各列の要約統計量の出力](#各列の要約統計量の出力)
    - [不均衡データのダウンサンプリング](#不均衡データのダウンサンプリング)
    - [特徴選択](#特徴選択)
    - [選択した特徴の傾向を視覚化](#選択した特徴の傾向を視覚化)
    - [ハイパーパラメータの選択](#ハイパーパラメータの選択)
    - [モデルをトレーニングして評価](#モデルをトレーニングして評価)
    - [データセットを利用して推論を再現](#データセットを利用して推論を再現)
- [リソースの削除](#リソースの削除)
- [まとめ](#まとめ)

## 事前準備

#### Kaggleのアカウントの準備
今回の手順で使用するデータセットを利用するには、Kaggleのアカウント作成が必要になります。 
まだアカウントをお持ちでない場合は、[kaggle](https://www.kaggle.com/) のトップページのRegisterよりアカウントを作成してください。  

#### 使用するデータセットのダウンロード
開催中のコンベンションのデータは取り扱えないため、今回は開催が完了している[Credit Card Fraud Detection](https://www.kaggle.com/mlg-ulb/creditcardfraud)のデータセットを使用します。 
規約に同意した上でコンベンションページのDownloadよりローカルマシンにダウンロードしてください。  
![kaggle_download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/773288de-6cf5-2ae0-6932-fa2225d6c7ba.png)

#### Azure環境の準備

GitHubより[Azure Machine Learning スタジオ](https://docs.microsoft.com/ja-jp/azure/machine-learning/overview-what-is-machine-learning-studio)の作成に必要な[Terraformコードとnootbookファイル一式](https://github.com/madaozaku/madaorepos/tree/main/azuremlstudio)をローカルマシンにダウンロードして実行します。
Terraformが面倒な場合は、公式の手順に従えば、そんなに手間もかけずに作成する事もできます。
ローカルマシンでAzureのTerraformコードを実行する手順は、[Azure環境の準備](https://fintan.jp/?p=7204#Preparation-of-the-Azure-environment) などを参照してみてください。
実行前に[init.tfvars](https://github.com/madaozaku/madaorepos/blob/main/azuremlstudio/terraform/init/init.tfvars)のprefixの値を固有の値になるように事前に編集します。既に使用済の値を指定した場合、この後のコマンドでエラーになります。
Terraformコードの実行例は以下の通りです。

```
$ cd ＜main.tfのあるフォルダ＞
$ terraform init
$ terraform plan -var-file init.tfvars
$ terraform apply -var-file init.tfvars
```
Terraformコードの実行が成功すると、以下のイメージのリソースがAzure上に作成されます。
![azure_all_resource.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/ac7f207a-282f-e593-3603-bab3efbef9b6.png)

#### コンピューティングの作成  

Azureポータルの「機械学習」のメニューより、先の手順で作成した[機械学習ワークスペース](https://docs.microsoft.com/ja-jp/azure/machine-learning/concept-workspace)を開きます。
![azure_ml_workspace.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/031ee185-57e8-2762-7445-3e773227c63f.png)
「Azure Machine Learningスタジオへようこそ」の画面が表示されます。
![azure_ml_studio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/bc9b6578-203f-13c0-a45f-fc0b6bdc3ca2.png)
「Azure Machine Learningスタジオ」を利用するには「コンピューティングインスタンス」の作成が必要になります。
左側の「コンピューティング」のメニューを開き、「コンピューティングインスタンスの作成」に進みます。
![azure_ml_computing.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/051c7a63-1739-7a90-cee0-bee973d7fdb4.png)
コンピューティング名、仮想マシンの種類、仮想マシンのサイズを選択してコンピューティングの作成を行います。
今回の例では、仮想マシンの種類はCPU、仮想マシンのサイズは「Standard_DS1_v2」でも十分です。
コンピューティングの稼働中は、課金が発生するため、使用しない間はコンピューティングを停止するようにしてください。  

#### 分析に必要な追加モジュールのインストール  

今回の分析に必要になる追加モジュールを「Azure Machine Learningスタジオ」上のターミナルより導入します。
 【今回の分析に必要になる追加モジュール】
 - [seaborn](http://seaborn.pydata.org/generated/seaborn.histplot.html#seaborn.histplot)
 - [imbalanced-learn](https://imbalanced-learn.org/stable/)
「Azure Machine Learningスタジオ」上のターミナルは「Notebooks」メニューを開くと起動する事ができます。  
![azure_ml_notebook.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/4753a660-b98b-0bdf-7a18-ca62454ff00c.png)
「Azure Machine Learningスタジオ」上のターミナルウインドウで以下のコマンドを入力して追加モジュールを導入します。

```
$ conda install seaborn
$ conda install -c conda-forge imbalanced-learn
```
導入後に「Azure Machine Learningスタジオ」上のコンピューティングを再起動してください。

## データの分析

#### 使用するデータセットについて

[Credit Card Fraud Detection](https://www.kaggle.com/mlg-ulb/creditcardfraud)コンベンションサイトの説明には以下の通りの説明が書かれています。  
> 【説明文を和訳して抜粋】
> データセットには、2013年9月にヨーロッパのカード所有者がクレジットカードで行った取引が含まれています。
> このデータセットは、2日間に発生したトランザクションを示しており、284,807件のトランザクションのうち492件の不正が発生しています。
> データセットは非常に不均衡であり、ポジティブクラス（詐欺）がすべてのトランザクションの0.172％を占めています。
> これには、PCA変換の結果である数値入力変数のみが含まれます。残念ながら、機密性の問題により、データに関する元の機能や詳細な背景情報を提供することはできません。
> 特徴V1、V2、…V28はPCAで得られる主成分であり、PCAで変換されていない唯一の特徴は「時間」と「量」です。
> 機能「時間」には、各トランザクションからデータセット内の最初のトランザクションまでの経過秒数が含まれます。
> 機能「金額」はトランザクション金額です。この機能は、たとえば、依存するコストに敏感な学習に使用できます。
> 機能「クラス」は応答変数であり、不正の場合は値1を取り、それ以外の場合は値0を取ります。

つまり、creditcard.csvのV1、V2、…V28とTime、amountのカラムのデータを利用して、classを推論するコンベンションとなります。
使用するデータの説明は、コンベンションサイトに詳しく掲載されていますので、そちらを事前によく確認します。

#### 新しいNotebookの作成

準備が整いましたので、これからデータの分析を進めていきます。「Notebooks」メニューの「作成」から「新しいファイルの作成」を選択します。
![notebooks_newfile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/86d4093b-01df-1f0e-baed-20e95dfdfa57.png)
新しいファイルに名前を付けます。今回は「creditcard.ipynb」（Jupyter Notebook形式）とします。

![notebooks_nwefile_create.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/bd3d1ad6-53ac-7174-7f11-a810c3679209.png)

Kaggleのコンベンションサイトからダウンロードしたデータセットをアップロードします。
「Notebooks」メニューの「作成」から「新しいファイルのアップロード」を選択してアップロードしてください。アップロードする場所は、「creditcard.ipynb」と同じフォルダ階層になるようにします。

![notebooks_uploadcsv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/ef8be76f-2f7e-d133-a783-87d07fa5510d.png)

#### 使用するライブラリの宣言

最初に使用するライブラリを宣言します。 今回は以下のライブラリを使用します。

|No |ライブラリ|説明|
|---:|---|---|
|1|[numpy](https://numpy.org/) |数値計算を効率的に行うための拡張モジュール |
|2|[pandas](https://pandas.pydata.org/) |データ解析を支援する機能を提供するライブラリ |
|3|[matplotlib](https://matplotlib.org/) |NumPyのためのグラフ描画ライブラリ |
|4|[seaborn](https://seaborn.pydata.org/) |[matplotlib](https://matplotlib.org/) を拡張した表現力の高いグラフ描画ライブラリ |
|5|[tqdm](https://github.com/tqdm/tqdm) |処理の進捗情報をプログレスバーとして表示するライブラリ |
|6|[sklearn](https://scikit-learn.org/stable/) |scikit-learnはPythonの代表的な機械学習のライブラリ |
|7|[xgboost](https://xgboost.readthedocs.io/en/latest/) |eXtreme Gradient Boosting 勾配ブースティングと呼ばれるアンサンブル学習と決定木を組み合わせたアルゴリズム |
|8|[imblearn](https://imbalanced-learn.org/stable/) |不均衡なデータのサンプリングに利用する |

最初のマークダウンのセルに以下のPythonコードを貼り付けて実行します。

```python
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pylab as plt
import seaborn as sns
from scipy.stats import mstats
from tqdm import tqdm
from sklearn import metrics, model_selection,feature_selection, ensemble, gaussian_process, linear_model, naive_bayes, neighbors, svm, tree, discriminant_analysis, model_selection
from xgboost import XGBClassifier
from imblearn import under_sampling, over_sampling

import warnings
warnings.filterwarnings('ignore')
```

実行すると以下のような画面イメージになります。
![notebooks_import.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/0dfbff5d-000d-5140-ee36-9712539aef3f.png)

#### データを視覚化

Pandasライブラリを使用してデータセットをロードして一部表示します。マークダウンのセルに以下のPythonコードを貼り付けて実行します。

```python
df = pd.read_csv('./creditcard.csv')
df.head()
```
データセットの中身がNotebook上に表示され、正しく読み取れている事が確認できるかと思います。  

![notebooks_df_head.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/79248e05-1fdb-b91b-7b1b-571fb1ce84fa.png)

#### 各列の要約統計量の出力

Pandasのdescribeのセルを実行して結果を確認します。マークダウンのセルに以下のPythonコードを貼り付けて実行します。

```python
df.describe()
```
データセットの各列の平均、標準偏差が表示されます。
![notebooks_describe.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/7b0fc5f6-a077-4b02-3659-631ae14ae345.png)

#### 不均衡データのダウンサンプリング

データセットは不均衡なデータになっているため、ダウンサンプリングして不均衡を解消します。
マークダウンのセルに以下のPythonコードを貼り付けて実行します。

```python
col = df.columns.tolist()
col.remove('Class')

positive_cnt = int(df['Class'].sum())
rus = under_sampling.RandomUnderSampler(sampling_strategy={0:positive_cnt, 1:positive_cnt}, random_state=0)
data_x, data_y  = rus.fit_resample(df[col], df[['Class']])
```

#### 特徴選択

推論の精度を向上させるために特徴選択をします。
マークダウンのセルに以下のPythonコードを貼り付けて実行します。

```python
feature_importance_models = [
    ensemble.AdaBoostClassifier(),
    ensemble.ExtraTreesClassifier(),
    ensemble.GradientBoostingClassifier(),
    ensemble.RandomForestClassifier(),
    tree.DecisionTreeClassifier(),
    XGBClassifier()
]

rfecv_col = pd.DataFrame(columns=['cnt'], index=col)
rfecv_col['cnt'] = 0

for i, model in tqdm(enumerate(feature_importance_models), total=len(feature_importance_models)):
    rfe = feature_selection.RFECV(model, step=3)
    rfe.fit(data_x, data_y)
    rfe_col = df[col].columns.values[rfe.get_support()]
    rfecv_col.loc[rfe_col, 'cnt'] += 1
```

#### 選択した特徴の傾向を視覚化

選択した特徴の傾向をseabornで可視化します。
マークダウンのセルに以下のPythonコードを貼り付けて実行します。

```python
x_col = rfecv_col[rfecv_col['cnt'] >= 4].index
sns.pairplot(df[x_col].sample(10000, random_state=1), kind='reg')
```

分析とグラフの生成が終わると、以下のような画面イメージが表示されます。
![notebooks_seaborn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/6aa4a34b-94a4-cbf7-8c4a-a1648715095c.png)

#### ハイパーパラメータの選択

今回は推論精度と実装のわかりやすさを重視して、ランダムフォレストを採用します。ハイパーパラメータをグリッドサーチで選択します。
マークダウンのセルに以下のPythonコードを貼り付けて実行します。

```python
model = ensemble.RandomForestClassifier()
param = [{
        'n_estimators': [10, 50, 100, 300], 
        'criterion': ['gini', 'entropy'], 
        'max_depth': [2, 4, 6, 8, 10, None],
        'oob_score': [True], 
        'random_state': [0]
        }]

best_search = model_selection.GridSearchCV(estimator=model, param_grid=param, scoring='roc_auc')
best_search.fit(data_x, data_y)
best_param = best_search.best_params_
model.set_params(**best_param)
```

#### モデルをトレーニングして評価

早速モデルのトレーニングと精度評価を行います。マークダウンのセルに以下のPythonコードを貼り付けて実行します。  

```python
train_x, valid_x, train_y, valid_y = model_selection.train_test_split(data_x, data_y, test_size=0.3, random_state=0)

model.fit(train_x, train_y)
pred = model.predict(valid_x)
fig, axs = plt.subplots(ncols=2,figsize=(15,5))

sns.heatmap(metrics.confusion_matrix(valid_y, pred), vmin=0, annot=True, fmt='d', ax=axs[0])
axs[0].set_xlabel('Predict')
axs[0].set_ylabel('Ground Truth')
axs[0].set_title('Accuracy: {}'.format(metrics.accuracy_score(valid_y, pred)))
fpr, tpr, thresholds = metrics.roc_curve(valid_y, pred)
axs[1].plot(fpr, tpr, color='red')
axs[1].set_title('ROC')
axs[1].set_xlabel('FP')
axs[1].set_ylabel('TP')
axs[1].grid(True)
plt.show()
```
![notebooks_modelfit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/43f640d2-949d-eaba-acf5-02b3cd636e8f.png)
それなりの精度が得られている事が確認出来ていると思います。  

#### データセットを利用して推論を再現

先ほどトレーニングしたモデルを使用して実際のデータセットを推論します。
マークダウンのセルに以下のPythonコードを貼り付けて実行します。

```python
pred = model.predict(df[col])
fig, axs = plt.subplots(ncols=2,figsize=(15,5))

sns.heatmap(metrics.confusion_matrix(df[['Class']], pred), vmin=0, annot=True, fmt='d', ax=axs[0])
axs[0].set_xlabel('Predict')
axs[0].set_ylabel('Ground Truth')
axs[0].set_title('Accuracy: {}'.format(metrics.accuracy_score(df[['Class']], pred)))
fpr, tpr, thresholds = metrics.roc_curve(df[['Class']], pred)
axs[1].plot(fpr, tpr, color='red')
axs[1].set_title('ROC')
axs[1].set_xlabel('FP')
axs[1].set_ylabel('TP')
axs[1].grid(True)
plt.show()
```
![notebooks_modelpredict.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/29c476f9-b06b-8b54-c0d3-7d0f0f774af0.png)
こちらも簡易的な実装にしては、それなりの精度が出来ていると思います。
実際のコンベンションに挑む場合は、より少ないリソースで高い精度を得るためのテクニックが必要になるかと思います。

#### リソースの削除

今回作成したAzureリソースを残しておくと、余計な課金額が発生してしまうため、作業を終える前に忘れずにリソースの削除を行います。  
削除するにはターミナルで「terraform destroy -var-file init.tfvars」と入力します。

```
$ terraform destroy -var-file init.tfvars
・・・（省略）
Destroy complete! Resources: 6 destroyed.
```

念のため、Azureポータルにログインして「すべてのリソース」メニューより、不要なリソースが残っていないか確認します。　　

## まとめ

このように、[Azure Machine Learning スタジオ](https://docs.microsoft.com/ja-jp/azure/machine-learning/overview-what-is-machine-learning-studio)を使用すると、 機械学習環境を簡単に構築できる事が確認いただけたかと思います。
[kaggle](https://www.kaggle.com/)では世界中の企業から常時様々なコンベンションが開催されており、以下のイメージのように開催中のコンベンションと賞金額が確認できます。  
![kaggle_competitions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/425848/940f41e3-f1e3-2397-e373-6518460f98b7.png)
これを機会に開催中のコンベンションに挑戦いただき、一攫千金を目指されてはいかがでしょうか。
わたしも、いつかはチャレンジしてみたいと思います。