DataRobot と Streamlit を使って爆速でかんたん機械学習アプリを作る

# はじめに
こちらは「[機械学習の自動化プラットフォームDataRobotを使って楽しむ冬のイベント予測チャレンジ 【PR】 DataRobot Advent Calendar 2020](https://qiita.com/advent-calendar/2020/datarobot)」の記事です。

今年も残りわずかですね。みなさん年末年始はどのように過ごしますか？
私はだらだらと過ごすことが多く、去年はこたつでバチェラーを見ていた気がします。
そして今年もコロナのせいでだらだら過ごすことになりそうなので、適当なアニメでも見ようと考えていたのですが、これを機械学習に選んでもらおうと思います。

しかし、年末までもう時間がありません。爆速でアニメ推薦アプリを作れる方法はないものか。
…
ありました。DataRobot と Streamlit です。

## DataRobot とは
DataRobot 社が提供する AI プラットフォームです。[公式サイト](https://www.datarobot.com/jp/platform/)には

>DataRobot のエンタープライズ AI プラットフォームを使用すれば、データサイエンスを民主化し、大規模な環境で AI を構築、デプロイ、メンテナンスするためのプロセス全体を自動化できます。最新のオープンソースアルゴリズムを採用し、クラウドやオンプレミスで、または完全管理型の AI サービスとして利用できる DataRobot なら、AI を活用してビジネスでより優れた成果を生み出せます。

と書いてあります。
AutoML (Automated Machine Learning) の先駆けで、データさえ用意すればほぼ全自動で機械学習モデルを作ることができます。

## Streamlit とは
Python でフロントエンドを構築することができるフレームワークです。[公式サイト](https://www.streamlit.io/)には

>The fastest way to build and share data apps
>
>Turn data scripts into sharable web apps in minutes. All in Python. All for free. No front-end experience required.

と書いてあります。
フロントエンドの知識がなくても簡単に Web アプリを作ることができます。

# 作ってみる
アプリのイメージは以下となります。

- 見たことがある中で好きなアニメを選ぶ（複数選択可）
- 選んだ以外のアニメがお薦め順に表示される

それでは作っていきましょう。

## データ準備
### データ収集

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488765/34b9bd45-4c17-d03e-3b88-46c722b6628b.png)

はじめは適当なサイトをスクレイピングしてデータを収集しようと考えていたのですが、なんと kaggle に「[Anime Recommendations Database](https://www.kaggle.com/CooperUnion/anime-recommendations-database)」なるデータがありました。こちらを使わせていただきます。
使ったファイル・列は以下となります。

anime.csv

- anime_id - アニメの ID
- name - アニメのタイトル
- type - 映画、TV、OVA など

ratings.csv

- user_id - ユーザの ID
- anime_id - 当該ユーザが評価したアニメの ID
- rating - 当該ユーザの評価 (1~10、見たけど評価しなかった場合は -1)

### データ加工
まずはデータ選択を行います。

- type が TV のアニメに絞り込み
    - だらだらと過ごすため、映画のような単発ものよりシリーズものがよい
- 50000 回以上評価されているアニメに絞り込み
    - あまりマニアックなアニメはお薦めされてほしくない + 簡単のため
- -1 の評価は除外

次はデータ形式の変換です。
詳細は本筋ではないので割愛しますが、イメージは以下となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488765/9a0513e1-b17f-36e4-908a-6583b3978f74.png)

推薦タスクの場合、データ形式をユーザ × アイテム行列にすることも多いと思うのですが、DataRobot ではターゲット列を設定する必要があるため、このような形式にしています（ターゲットは"rating"）

最終的に 234613 行 × 239 列の「train.csv」ができあがりました。

## モデル作成
DataRobot で機械学習モデルを作っていきます。
DataRobot は有償サービスなのですが、ググると[フリートライアル](https://www.itis.nssol.nipponsteel.com/datarobot/solution/datarobot/free-trial/)があるようです。申し込んでみましょう。
使い方に関しては[学習教材](https://community.datarobot.com/t5/%E3%82%AA%E3%83%B3%E3%83%87%E3%83%9E%E3%83%B3%E3%83%89%E3%83%93%E3%83%87%E3%82%AA%E5%AD%A6%E7%BF%92%E6%95%99%E6%9D%90/bg-p/jp07a/label-name/%E3%83%95%E3%83%AA%E3%83%BC%E3%83%88%E3%83%A9%E3%82%A4%E3%82%A2%E3%83%AB)や他の方の記事が参考になります。

### データアップロード & モデル作成
「train.csv」をアップロードして、ターゲットに"rating"を設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488765/117c75d2-b06e-32a7-2d56-7a6e7dab3499.png)

あとは開始ボタンを押すだけで、様々なモデルが全自動で作られます。

### モデル確認

作られたモデルのランキング表を確認します。
上位のモデルは MAE (平均絶対誤差) が 0.87 となっています。つまり、「こういう人はこのアニメに何点を付ける」という予測を平均 0.87 点の誤差で行えているということです。悪くなさそう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488765/bc3df234-f8ab-4789-d8cf-b5adec96b290.png)

モデル名をクリックすると、より詳細な評価を、様々な観点で確認することができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488765/52b5b46a-9a67-648e-712a-aefa67e5067d.png)

### モデルデプロイ
今回はアプリを作るため、モデルの予測機能を外部プログラムから呼び出せるようにする必要があります。"モデルをデプロイ"すれば、当該モデルの予測機能が API 化されます。これはかなり便利。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488765/eb041345-b314-bd42-1ae4-34a31f6803f0.png)


予測用の Python スクリプトまで提供されます。
今回のアプリには本スクリプトを流用するため、「datarobot_predict.py」として保存しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488765/ed565daf-3400-67ed-b463-e16504deebd1.png)

## アプリ作成
Streamlit で Web アプリを作っていきます。
まず、Streamlit をインストールします。

```
pip install streamlit
```

次に、[Get started](https://docs.streamlit.io/en/stable/getting_started.html) や [API reference](https://docs.streamlit.io/en/stable/api.html) を参考にしながら Python ファイルを作ります。
先ほど保存した「datarobot_predict.py」をインポートし、関数を流用しています。

```app.py
import numpy as np
import pandas as pd
import streamlit as st
import datarobot_predict as drp


DEPLOYMENT_ID = "xxxxx"


@st.cache
def load_data():
    anime = pd.read_csv("../data/prep/anime.csv")
    return anime.set_index("anime_id")


st.title("Anime Recommender")

# load data
anime = load_data()

# select animes
selections = st.multiselect(
    "select your favorite animes",
    anime.index.tolist(),
    format_func=lambda x: anime.loc[x, "name"],
)

# predict
if st.button("Go"):
    test = anime.copy()
    test[test.index] = np.nan
    test[selections] = 10

    res = drp.make_datarobot_deployment_predictions(
        test.to_csv().encode("utf-8"), DEPLOYMENT_ID
    )
    pred = [res["data"][i]["prediction"] for i in range(len(res["data"]))]
    test["score"] = pred

    test.sort_values("score", ascending=False, inplace=True)
    st.write("### DataRobot's recommendation")
    st.write(test[~test.index.isin(selections)][["name", "score"]])

```

上記ファイルを実行すれば、ブラウザ上にアプリが開きます。

```
streamlit run app.py
```

# アニメ推薦アプリ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488765/b1ca8892-9955-d12f-23d3-7a81732ac5ae.png)

プルダウンから、私が見たことある中で好きなアニメを選んで、Go ボタンを押してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488765/dfe1856e-bb6f-4cfa-45c7-549a509a292d.png)

私が選んだのは

- ひぐらしのなく頃に
- 夏目友人帳
- 化物語
- 四月は君の嘘

でした（ちなみに私はアニメに詳しくなく、かなりのメジャーどころしか見たことがありません）

それに対して推薦されたのは以下でした。

- 〈物語〉シリーズ セカンドシーズン
    - 「化物語」を選んでいるので納得
- HUNTER×HUNTER
    - アニメは見たことないけどマンガは好きで全巻持っている
- 鋼の錬金術師
    - アニメは見たことないけどマンガは好きで全巻持っている
- STEINS;GATE
    - 見たことないけど興味はあった
- 蟲師
    - 知らない
- 天元突破グレンラガン
    - 見たことないけどパチンコは好き。笑
- CLANNAD AFTER STORY
    - 見たことあって最後のほうだけ好き
- コードギアス 反逆のルルーシュR2
    - 見たことないけどパチンコは好き。笑
- etc.

良い感じですね！
欲を言えば、上位 3 つは当たり前なものや、おそらく誰でも高評価なものなので、推薦されなくてもよいと思いました。
データ形式を工夫したり、推薦順を (予測値 ÷ 当該アニメの評価の平均値) にすれば、もう少しセレンディピティが起こりやすくなるかもしれません。
これは今後の課題とさせてください。

# おわりに
DataRobot も Streamlit も本当に簡単でした。特に DataRobot は商用でも（というか商用でこそ）有用だと思います。

そして、年末年始のお供は「STEINS;GATE」か「蟲師」にしようと思います。