DataRobotを使って機械学習を自動化する

#はじめに
 初めまして。今回は私の新卒として初めて携わった業務である、DataRobotを使った機械学習の自動化についてお話しいたします。機械学習に取り組む際に必ずしもDataRobotをオススメするわけではないということをご了承の上、お役に立てられる方が一人でもいらっしゃったら幸いです。


##DataRobotとは
 DataRobotは機械学習およびプログラミングに関する知識を必要とせず、データを与えるだけで最適なモデルを構築してくれる機械学習プラットフォームです。DataRobotの特徴の一つとして、機械学習に最も時間を費やすとされる未加工データの変換プロセスを、自動的に探索的分析を実行することが挙げられます。与えられたデータの各変数タイプを識別し、平均、中央値、標準偏差など、数値レコードの統計的記述を生成します。これによって、ユーザーはExcelなどで手動でデータ分析することなく、データを探索したり、欠損値の自動補完を行います。
 今回はpythonからDataRobotに教師データを送り、学習し、モデルをデプロイして、予測するまでの一連の流れを記述したいと思います。

##データ準備
今回はKaggleで提供されているtitanicのデータを使って、生存者を分類する問題を解きたいと思います。

|Columns|Passengers_id  |Survived  |Pclass  |Name|Sex|Age|SibSp|Parch| Ticket|Fare|Cabin | Embarked|  
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|表記例|1  |0  |3  |Braund, Mr. Owen Harris |male |22|1|0|A/5 21171|7.25||S|
|説明|乗客ID  |生存者フラグ  |チケットクラス |氏名|性別 |年齢|兄弟・配偶者の乗客数|親・子の同乗者数|チケット番号|乗船料金|客室番号|搭乗港|

この教師データで言えば、生存者フラグ(0=死去,1=生存)を他のカラムから予測し、モデルの精度を検証します。なお、Kaggleは予測結果を提出すると実際の結果からスコアを出してくれるので、そちらも少し参考にしたいと思います。

##スキーマ定義
入力データの型を定義します。ラベルデータや学習に含まないデータ, NULLの場合の挙動をここで決めます。

```yaml:schema.yaml 
schema:
  PassengerId:
    type: int
    drop: true
  Survived:
    type: int
    target: true
  Pclass:
    type: int
  Name:
    type: str
  Sex:
    type: str
  Age:
    type: float
    nullable: true
  SibSp:
    type: int
  Parch:
    type: int
  Ticket:
    type: str
  Fare:
    type: float
    nullable: true
  Cabin:
    type: str
    nullable: true
  Embarked:
    type: str
    nullable: true
```

##プロジェクト作成

DataRobotは教師ラベル一つにつき一つのプロジェクトという単位で管理します。プロジェクトは必ず一つのデータセットを持ち、学習モデルやモデルのデプロイからモデルを使った予測まで、プロジェクトの中で行われます。最初にデータセットを送り、プロジェクトを作成します。

```python
import datarobot

def create_project(df, project_name):
    return datarobot.Project.create(df, project_name=project_name)
```

次にデータセットの特徴量のリストを作成します。

```python
def create_featurelist(project):
    features = set(project.get_featurelists()[0].features)
    return project.create_featurelist(name='subset', features=list(features))
```

これが終了すると、DataRobotの画面上でデータが読み込まれているのが表示されます。
<img width="1190" alt="スクリーンショット 2019-12-20 10.46.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447366/3ea939a0-0b21-69e9-75af-055ef870cebb.png">
これを見ればわかるように、DataRobotは読み込まれたデータの中から、平均や標準偏差などの統計量や欠損値数など自動で読み取ってくれます。


##学習
続いて学習を始めます。学習は特徴量のリストとラベルデータ(ターゲット)を指定することで実行できます。ここではfeaturelistに元のスキーマ定義からターゲットが指定されている場合を想定しています。

```python
def train(project, feature_list):
    return project.set_autopilot(featurelist_id=featurelist.id) 
```

これを実行するとDataRobotの中のオートパイロットという機能が学習を開始させます。
<img width="1425" alt="スクリーンショット 2019-12-20 10.33.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447366/befcae58-78a8-3025-5dc6-77af94772c32.png">
画面上で言えば右側の「ワーカー」という項目の下にオートパイロットの実行状況が表示されます。

## モデルの見方
学習が終了すると、モデルがいくつか表示されます。DataRobotの特徴の一つとして、モデルの解釈可能性をブループリントで表示してくれるところです。
例えば特徴量ごとの重要性については、このように表示されます。
![Gradient Boosted Greedy Trees Classifier 80.02％のサンプルサイズ 特徴量のインパクト.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447366/91568c2b-90c6-5f84-7000-959a318ca944.png)
この例だと、生存したかどうかに与えられた名前が重要というちょっと謎に思うのですが、ワードクラウドで部分ごとに文字を解釈するとこのようになります。
!['Elastic-Net Classifier (L2 _ Binomial Deviance)' WordCloud.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447366/7846ef5d-3624-e2b8-56f1-867b0f54b776.png)
ここで文字の大きさはその文字の頻度、色は赤い色ほど重要度が高いことを示していますが、miss=未婚の女性、mrs=既婚の女性という、女性を表す敬称が生存するかどうかに重要だということになります。実際の現場でも、女性優先で救助が進められたのでしょうか。性別や年齢のカラムがあるにも関わらず、名前に含まれる敬称で判別するのは面白い結果です。

##デプロイ
さて、モデルを作ったので予測までさせてしまいましょう。まずモデルをデプロイして、利用できる状態にさせます。

```python
def deploy(project):
    recommended_model = datarobot.ModelRecommendation.get(project.id).get_model()
    return datarobot.Deployment.create_from_learning_model(model_id=recommended_model.id)
```
ここでrecommended_modelはdataRobotの中でデプロイを推奨するモデルを選定してくれます。そのモデルIDを渡すとそのモデルがデプロイされます。

##予測
予測用のデータもKaggleで提供されていますので、そちらを使用します。

```python
def predict(test_data, deployment_id):
    url = 'https://{endpoint}/predApi/v1.0/deployments/' \
          '{deployment_id}/predictions'.format(
            endpoint=self.endpoint,
            deployment_id=deployment_id)
    # Make API request for predictions
    predictions_response = requests.post(
       url, auth=(self.username, token), data=csv)        
    # Return a Python dict following the schema in the documentation
    return predictions_response.json()    
```
ここではユーザーネームと予測用のAPIトークン、endpointを渡し、レスポンスとして予測結果をcsv形式でダウンロードします。

##結果
予測した結果をKaggleに送りました。
<img width="936" alt="スクリーンショット 2019-12-20 12.05.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447366/2b3197e6-29a6-6821-e478-b1b9e652a34a.png">
…微妙でした。しかし、一般的な機械学習のアルゴリズムで試した時(下記)よりも良い結果になっていたので、この辺はモデルの解釈性の違いになります。今回のモデルは乗客者の氏名に着目したモデルなので、差別化はできるかと思います。
<img width="939" alt="スクリーンショット 2019-12-20 12.08.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447366/a4d5877e-51e8-6c96-a0a5-bafea70b2428.png">

#まとめ
DataRobotは品質と操作性を兼ね備えた機械学習プラットフォームです。またAPIも豊富で、機械学習フローの自動化に大きな役割を果たしています。データサイエンティストが多くの時間を費やしてきたデータ加工なども簡単に行うことができ、熟練データサイエンティストから機械学習エンジニア初心者でも取り扱えます。他の機械学習ツールと比較して高額なのがネックなので、今後はDataRobotを超えるようなモデル開発に取り組みたいと思っております。