Dataiku AcademyのUse Case: Predictive Maintenanceをやってみる

## はじめに
Dataiku DSSの使い方を学ぶのに最適なコンテンツとしてDataiku AcademyのFoundational Learningがある。しかし内容はすべて英語のため、読むのは面倒だという方のために実際にやってみて手順をまとめる。
今回やったのは[Use Case: Predictive Maintenance](https://academy.dataiku.com/latest/usecases/L01C01/index.html)。

## 概要

### 想定するユースケース
このユースケースではレンタカー会社のデータサイエンティストとして、自動車修理の予測を行う。
レンタカーを貸し出している最中の故障はとてもコストがかかるし、客にも迷惑がかかる。そのため、故障しそうな自動車を予測することで、これらの問題を解決したい。
今回、過去の故障の情報やメンテナンスの記録が手に入っているので、それらを用いて以下の2つの問いへの答えを導く。

- もっとも一般的な故障の原因は何か
- どの自動車が故障しそうか。

### 使用するデータ
今回のユースケースでは、以下の3つのデータが配布されている。(リンクをクリックすることでダウンロード可能)

- [usage](https://downloads.dataiku.com/public/website-additional-assets/data/usage.csv.gz): 自動車が運転された距離(マイル)のデータ。様々な時点で記録されている。
- [maintenance](https://downloads.dataiku.com/public/website-additional-assets/data/maintenance.csv.gz): 自動車の修理のデータ。いつ、どのパーツを、何個、なぜ修理したのかが記録されている。
- [failure](https://downloads.dataiku.com/public/website-additional-assets/data/failure.csv.gz): 自動車が故障したかどうかのデータ。すべての記録がされているとは限らないので注意。

今の段階ではデータがどのようなものかは何となくわかっていれば良い。

### ワークフロー概要
このユースケースを完了すると以下のようなフローがDataiku DSSで完成する。
![workflow_overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/4f0a1196-7288-b873-7afa-840730fdec3e.png)
このユースケースを実施することで、以下の5つを主に学ぶことができる。

- データのインポート
- データクリーニング
- データの結合、分割
- 故障の予測を行う機械学習モデルの作成
- ラベル無しデータへの機械学習モデルの適用

もちろん、書かれていることだけでなくいろいろ試してみることも大切なので、このフロー通りにすることにこだわる必要はない。
Dataiku Academyの[Tutorial: Basics](https://academy.dataiku.com/latest/tutorial/basics/index.html)と[Tutorial: From Lab to Flow](https://academy.dataiku.com/latest/tutorial/lab/index.html)を先にやっておくと、より理解しやすいかもしれない。

## ユースケースの詳細手順
### プロジェクトの作成とデータのインポート
始めにDataiku DSSにプロジェクトを作成して、データをインポートする。
データは上のリンクからダウンロードできる。
この辺はもうわかっているから簡単だという人は次のステップに進んでしまっても問題ない。

1. "+ NEW  PROJECT"をクリックし、"Blank project"を選択。Nameに`Predictive Maintenance`と入力し、"CREATE"をクリック。
(プロジェクト名は何でも構わないが、日本語の名前を付ける場合は、プロジェクトキーも自分で入力する必要がある。プロジェクトキーは日本語不可)

![new_project.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/0972f82d-d83b-6d75-7440-f98eed78f83f.png)
2. "+ IMPORT YOUR FIST DATASET"をクリックし、Fileの中の"Upload your files"を選択。データアップロードエリアに_usage.csv.gz_をドラッグ&ドロップ。
念のため"PREVIEW>"をクリックし、データが適切に読み込まれているか確認。問題がなければ、右上の"CREATE"をクリック。
![upload_file_usage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/efe9c37b-0610-364c-41fa-668306f7af2f.png)
3. フロー画面に戻り、右上の"+DATASET"→"Upload your files"を選択。_failure.csv.gz_および_maintenance.csv.gz_も同様の方法でインポートする。
4. データのインポートが終わった状態のフローは以下のようになる。
![flow_data_import.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/7be3853c-d320-01fd-6ef5-94af22f46c91.png)

### _usage_データセットの前処理
_usage_データセットについて

- _Use_は_Time_の時点で自動車が走った距離(マイル)の合計を記録したもの
- _Time_はそのデータを記録した時を表しているが、その単位は不明。もしかするとある日付からの経過日数かもしれないが、本来であればデータを取った人に確認をとる必要がある
- _Asset ID_は資産番号であるが、このデータセットでは資産番号でデータが一意には定まらない

インポートしたcsvファイルでは、それぞれの列がstring型で保存されているが、Dataiku DSSはtext, integer, decimalなどデータの型を認識することができる(青い文字で書かれているのが認識した型である)。
![data_type.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/5e88d847-6490-29e0-046e-d3b1c0433a78.png)
保存された型がstringのままでは数値的な操作を行うことができないので、それをまずは修正していく。

1. "Settings"タブをクリックした後、"Schema"を選択する。
![setting_tab.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/50ac9b9a-a5eb-83ac-2213-31ea176f4ae5.png)

![setting_schema_tab.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/d86053f6-c8bc-773d-6732-ed68b0bd6d5e.png)
2. "Check Now"をクリックすることでデータを正しい型に定める。
![check_now.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/7b2e19e4-a1c0-81be-d51b-c4ff2bc969b8.png)
3. "Infer Types from Data"をクリックして変更した型を確定させる
![infer_types_from_data.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/fb39247c-8fe0-c2d3-24a4-95c6bf8e1baa.png)

Explore画面に戻ると、データの型が変更されているのがわかる(グレーの文字で書かれた型名が変更されている)。
![data_type_change.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/fa1beacc-6a3b-39c2-b5a2-9bc441c3664d.png)
それぞれの自動車は複数の時点で_Use_が記録されているが、モデルを作成する際には一つの自動車に一つのレコードであることが望ましい。そこで、recipeを用いてデータを集約する。

1. _usage_データセットをクリックし, Action menuから"Group"を選択する。![action_group.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/f9ff0c71-fe3a-2f62-9573-9f1f9d650ed3.png)
2. Group Byに_Asset_を選択する。
3. アウトプットにはデフォルト`usage_by_Asset`のまま。
![group_new.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/f36ddf75-2a89-1cdf-92b7-1c5485751f01.png)
4. Group Keysの部分はデフォルトのまま、Per field aggregationsの部分では_Time_および_Use_の両方で"Min"と"Max"を選択する。
![group_main.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/1d1b59c6-87c2-2007-85c7-fddd4cd9cc7c.png)
5. "RUN"ボタンを押してこのレシピを実行することで6列のデータセットが出力される。
![usage_by_Asset.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/3dd8387b-d5e3-57e4-3291-3c4343d36568.png)

### _maintenance_データセットの前処理

_maintenance_データセットは_Asset_ごとに_Part_(何を直したか)、_Time_(いつ直したか)、_Reason_(故障の原因を表すコード)で構成されている。
_usage_データセットの時と同様、一つの自動車に一つのレコードとなるように前処理を行う。しかし、ここで使用するのはGroupレシピではなく、Pivotレシピを用いる。

1. まず、_usage_データセットにも行ったように、データの型の認識を行う。
2. 次に、ACTIONメニューから"Pivot"を選択する。
![action_pivot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/1095e8f0-c633-a0c6-4f2a-fdfcf3b14a0d.png)
    - Inputには_maintenance_を入力し、Pivot Byには_Reason_を選択する
    - Outputはデフォルトで入力されている`maintenance_by_Reason`のまま"CREATE RECIPE"をクリック。
    ![pivot_new.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/18f15f43-1217-f473-e733-840d60facf89.png)
    - Row identifiersに_Asset_を選択する。
    - Create columns withには_Reason_が既に選択されているのでそのままで、Pivot valuesを"all"に変更する。
    - Populate content withはCount of recordのチェックは外し、"sum(Quantity)"を選択する。 
    ![pivot_main.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/3cd8e44e-86c5-84af-8c48-1c8054377f51.png)
3. "RUN"を押して、recipeを実行する。 

![maintenance_by_Reason.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/4334245a-36d1-de0f-c290-4e34f1a659ea.png)

### _failure_データセットの前処理
_failure_データセットは_Asset_と_failure\_bin_の2列のみで形成されたデータセットである.

- _Asset_はすでに1つのIDに対して1つのレコードというデータにになっている。
- _failure\_bin_は0または1で_Asset_が故障したかどうかを示している。この変数を、予測モデル作成時のラベルとして使用する。

ここでは、前2つのデータセットに対しても行った、データの型認識のみを行えばよい。

### データセットの結合
ここまでで、3つのデータセットすべてを_Asset_ごとに記録されたデータに変更したので、次に行うのは、これらのデータセットの結合である。それぞれのデータセットには共通して_Asset_が存在するため、簡単にデータセットを結合させることができる。

1. _failure_をクリックし、ACTIONメニューから"Join with"を選択する。![action_join.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/29123f22-9980-077c-b45c-1f911794d7b6.png)
2. Inputに_usage\_by\_Asset_を追加する。
3. Outputには`data_by_Asset`と入力し、"CREATE RECIPE"をクリックする。
![join_new.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/ab0545bf-99ea-cd3a-6282-31902717608f.png)
4. 画面右上の"+ADD INPUT"をクリックし、3つ目のInputとして_maintenance\_by\_Reasons_を追加する。![join_add_input.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/66a3b579-1e12-bda7-0a14-542bf8c673d8.png)
5. デフォルトで設定されているのがどちらも__Left Join__であることと、_Asset_がキーになっていることを確認する(違う場合はルールの部分をクリックして設定を変更する)。
6. "RUN"を押して実行。21列のデータセットが出力される。
![join_main.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/3f7474b5-8b2f-6c13-90fb-dc86a402d7d1.png)

出力された_data\_by\_Asset_は_maintenance_と_usage_、_failure_の情報を持ったデータセットである。
![data_by_Asset.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/999d8d5e-5ed4-4ac4-0438-350b04da9a6e.png)

### 学習用&評価用データセットの作成

モデルを学習するために、Splitレシピを用いて_data\_by\_Asset_を2つに分け、_training_と_scoring_を作成する。

- _training_データセットは学習用のデータセットであり、故障したかどうかを判別するためのラベルがついている。
- _scoring_データセットには、故障したかどうかを示すラベルがついていないため、作成したモデルを用いて故障する確率の高い自動車を予測する。

Splitの手順は以下の通り。

1. _data\_by\_Asset_をクリックし、ACTIONメニューから"Split"を選択。
![action_split.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/e49c0d0d-6155-62be-0c5c-c235f17f5d74.png)
2. "+ADD"からOutputに`training`と`scoring`と追加し、"CREATE RECIPE"をクリック。
![split_new.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/86c3c319-9dcc-09fc-65d3-25fa1b11ef62.png)
3. Select Splitting methodでは、"Map values of a single column"を選択。その後の画面で、Split on columnに_failure\_bin_を選択。based onはデフォルトの"Discrete values"のまま。
4. Valueに`0`, `1`を入力し、それぞれOutputには_training_を選択する。Other valuesのOutputは_scoring_にする。
5. "RUN"でレシピを実行する。
![split_main.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/17d53c56-1d01-8f47-fee3-62d70f0b8502.png)

この例では、_scoring_に分けたラベル無しのデータがなぜラベルがないのかは不明確である。ランダムに抜けているのか？それとも意味があって入力されていないのか？実際のデータ分析では非常に重要な点であるが、何も答えを得ることができないのでここでは気にせず進めることとする。

### 特徴量の生成
trainingデータセットを用いてモデルの作成を行う前に、いくつかの有益な特徴量を生成する。
今度は、試行錯誤をしながらデータセットの処理を行いたい場合に使用する__Lab__機能を用いる。Labを用いることで、ワークフローに新たなデータセットを追加することなくデータの加工を行うことができる。Labについてもう少し詳しく知りたい場合は、チュートリアルの[Lab-to-Flow](https://academy.dataiku.com/latest/tutorial/lab/index.html#discover-the-lab)を確認する。

1. _training_データセットをクリックし、ACTIONメニューから"LAB"を選択する。
![action_lab.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/40ac0e6b-75ca-8c04-7161-7a20c400b440.png)
2. 出てきた画面で、Visual analysis側にある"NEW Prepare data and build models"を選択する。入力する名前はデフォルトの`Analyze training`のままでよいので、"CREATE"をクリックする。
![lab_new.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/328744d6-481f-3b7a-6bcb-935aaa2c833a.png)
3. するとPrepareレシピのような画面になる。ここで、2つの新しい変数をformulaを用いて作成する。
    - `distance`: _Use\_max_ - _Use\_min_
    - `time_in_service`: _Use\_max_ - _Use\_min_
    
![lab_formula.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/154f7e20-6bce-3bee-28cd-19709d6d3b98.png)
4. Fill empty cells with fixed valueを使用して、_Reason_で始まる列の空の部分を、0で埋める。この時、列名の指定には、正規表現`^R.*_Quantity_sum$`を用いる。
   ![lab_fill.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/a50798e5-44f5-1c3b-5f5e-53badfe2052f.png)
5. 最後に、作成するモデルの結果を見やすくするためにRename Columnsを用いて、列名を修正する。

|変更前|変更後|
|:--|:--|
|count|times_mesured|
|Time_min|age_initial|
|Time_max|age_last_known|
|Use_min|distance_initial|
|Use_max|distance_last_known|

![lab_rename.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/fc767622-a4b3-7b35-e0f4-6e29be51df7a.png)

### 予測モデルの作成
ここまでで学習モデルを作るための準備が整ったので、機械学習を使って自動車の故障を予測していく。
今、LabのScriptタブにいるので、上のタブからModelsタブに移動し、"CREATE FIRST MODEL"をクリックする。すると以下のどちらかを選ぶ画面が表示される。

- Prediction(予測・教師あり学習): 与えられた特徴量から、目的変数を予測する。
- Clustering(クラスタリング・教師なし学習): 共通のパターンや特徴に基づいてグループを作成する。
 
今回の場合はレンタカーが故障するかどうかを予測したいため、Predictionを選択する。
すると、目的変数を何にするか選ぶ画面になるのでSelect your target variableにおいて、_failure\_bin_を選択する。
その後、"Automated machine Learning", "Quick Prototypes"と選択していき、"CREATE"を押す。
![model_choose.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/6f74c433-8479-3673-24c2-5cb467b8be75.png)
![model_quick.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/47493d13-65f0-6a7f-bcbb-f5c7ee30783f.png)
後は、画面真ん中の"TRAIN"ボタンをクリックするだけで、学習が始まる。
ここで、余裕のある人はDESIGNタブに移動し、MetricsやFeatures handling、Algorithmsなどの設定をいろいろ試してみると、より良いモデルを作成できるかもしれない。

###モデルの理解
学習が終わると、学習結果の概要がわかるような画面が表示される。設定した指標でモデルを評価し、一番精度の高かったモデルにはトロフィーマークがつく。今回の場合は、Random forestというモデルがROC AUCという指標で評価した場合に、一番性能の良いモデルという結果になった。
![model_training.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/9da88608-57f5-567f-6e4f-1b378addc79e.png)
それぞれのモデルの詳細を知りたい場合は、そのモデル名をクリックすることで見ることができる。
今回は、一番性能の高かったモデルの詳細を確認するため、"Random forest"をクリック。すると以下の画面になる。
![model_random_forest.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/ea02c99d-d982-f640-2655-e1c23fdefd3a.png)
左側のサイドバーから見たい項目を選んで確認していく。今回は主に確認するべき項目をいくつか紹介する。

- Variable importance: どの特徴量がどれだけ予測に影響しているのかを見ることができる。
![model_importance.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/37aa1649-9feb-d5d2-9c57-ad2df7408342.png)
- Confusion matrix: モデルの精度についての詳細を見ることができる。
![model_confusion.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/90571fab-21f1-1c5f-037e-33380c4c9ad3.png)
- Decision trees: 決定木系のモデルの場合、使用された決定木を見ることができ、学習の段階でどのように分類されたのかを確認することができる。(ランダムフォレストの場合も見ることができるが、木の数が多いためすべてを表示することはできない。)
![model_tree.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/ee5503c2-c91b-80c5-b458-954915982fbd.png)

今回作成したモデルでは、Variable importanceを見てみると、_R193\_Quantity\_sum_、_time\_in\_service_、_age\_initial_などが故障に大きく関係していることがわかる。

### モデルの使用
作成したランダムフォレストモデルを使用して、ラベル無しデータである_scoring_データセットの予測を行う。

1. モデルページの右上にある"DEPLOY"ボタンをクリック。
![model_deploy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/1b658bf6-7c9a-94f1-d216-1d50cb55f929.png)
2. 表示された画面では、すべてデフォルトのまま"CREATE"をクリック。
![model_deploy_dialog.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/7fffa5a7-da2a-e94d-d1b2-e08776eacadd.png)
3. ワークフローの中にモデルが作成される。緑のアイコンの_Prediction (RANDOM\_FOREST\_CLASSIFICATION) on training_をクリックしACTIONメニューから"Score"を選択。![action_score.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/a22cc176-8127-90b3-f558-f533e49bc58f.png)

4. Input datasetに_scoring_を選択し、Outputは`scored`と入力する。Prediction Modelはデフォルトのまま"CREATE RECIPE"をクリック。
![score_new.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/20388e93-75dc-96c9-4a2c-4f3d203e0f80.png)


5. 表示された画面ではすべてデフォルトのまま"RUN"ボタンを押して実行。
![score_main.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/2ecbe532-c98d-7c01-d3f6-4cb7e2b70b5c.png)

作成された_scored_データセットには3つの新しい列が追加されている。
![scored.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442306/2fc44bdb-b656-15a5-5c99-afff34e22762.png)

- proba_1: 故障する確率
- proba_0: 故障しない確率(1-proba_1)
- prediction: モデルが予測した結果(確率の閾値をもとに決定される)

以上で、このUse Case: Predictive Maintenanceは完了。

## おわりに
自動車の故障の予測を行うまでの流れをDataiku DSSを用いて実行する方法を学んだ。
ここでは、Dataiku DSSのデフォルトの設定で予測を行ったが、このモデルにはまだまだ改善の余地がある。具体的には

- データセットの情報を組み合わせて新たな特徴量を作成する。
- 他のアルゴリズムを使用したり、パラメータを変更したりする。

などが考えられる。

Dataikuが公式でこのユースケースの[サンプルプロジェクト](http://gallery.dataiku.com/projects/DKU_PREDMAINT_ML/)も用意しているので、わからないところがあったり、より理解を深めたい場合は是非参考に。