こんにちは、エンジニアの建三です。僕は大学時代に人工知能に興味を持ち、卒業後も機械学習を勉強していました。ただイタンジに入って業務で機械学習を使ってみて思うのは、勉強でやる機械学習と実務でやる機械学習にギャップがあるなということです。
機械学習を普通どうやって勉強するかというと、まず機械学習の基礎を学び、その後色んなアルゴリズムを勉強します。その際、どのデータを使って何がゴールかというのは与えれていて、アルゴリズムの仕組みを勉強することに大半の時間を費やします。
しかし俗に言われるデータサイエンスの業務をやるとなると、他に必要なことがあります。僕の中でデータサイエンスの業務はざっくりと4ステップに分かれます。
- 問題定義
- データの選択、収集
- モデルの構築、学習
- 結果のアウトプット
機械学習を勉強する時は、大抵3と4だけをやることになります。しかし1と2が結構重要なので、それぞれについて触れたいと思います。
Step1.問題定義
データサイエンスの業務は、問題の定義から始まります。会社でどういう問題を抱えてて、何がゴールなのかを知る必要があります。これはデータサイエンティストが考えることよりも、経営陣とかマネージャーからふわっとした要望が来ることの方が多いと思います。
今回イタンジではファネル毎のユーザーの分析をしました。どんなビジネスでもファネルというものが存在します。消費者がサービスを知ってからお金を払う顧客になるまでの大きな段階のようなものですね。
弊社の無店舗型不動産サービス「ノマド」でいうと、ファネルは以下のようになります。
- LPへの流入
- 会員登録
- 気に入ったお部屋が空室かどうか問い合わせ
- お部屋の内見
- 申し込み
- 成約
今回、2→3と3→4のフェーズで、以下の2つの問いに答えられないかという要望が上がりました。
- 次のフェーズへ進むユーザーと進まないユーザーを予想することは出来るか?
- 次のフェーズへ進むユーザーと進まないユーザーの違いは何か?
これはどちらも機械学習を使って答えることが出来ます。1は分類(Classification)です。最もよく使われる機械学習のカテゴリですね。 2は特徴選択(feature selection)というものです。こちらは分類の精度を上げる為の過程で使われることが多いですが、これ単体でも役に立ちます。
こうやって書くと単純に見えますが、実はこの「ビジネスの問題を機械学習のタスクに落とし込む」というのが意外に難しいです。これはデータサイエンスに限らず何でもそうだと思うんですが、学校で学んだものを実社会に役立てるにはそれなりの訓練が必要だなと思います。
Step2. データの選択、収集
問題定義が出来たら今度は何のデータを使うかを考えなければなりません。今回のタスクは顧客に関するものなので使えるデータの種類が沢山ありますが、逆に沢山あり過ぎてどれを使ったらいいか考えるのが大変です。
教科書で学ぶ機械学習だと、既にデータが用意されてあって、クラスを分類する際にどの特徴が一番重要かというのをエントロピーを使って出したりします。しかし実際は、使えるデータを全て収集するのに時間がかかります。単純に顧客データと言っても複数のテーブルに渡って関連データが入っているので、一つのテーブルをCSVに出力してはい終わりというわけにいきません。なのでどのデータが重要かある程度仮説を立てる必要があります。ここでは業務をドメイン分析する知識が必要不可欠です。
Step3. モデルの構築、学習
データを集めたら遂にモデルの構築です。実際は追加で必要なデータを取ってきたり、処理しやすいようにSQLのクエリを書き直したりといった作業が入るので、Step2と被る部分があります。僕はPythonを使ってますが、どこまでをSQLでやってどこからPythonで処理するかというのも判断が難しい時があります。
このステップに関しては、それぞれのフェーズ毎にお話しします。
登録→問い合わせ
登録から問い合わせのフェーズを分析する際に僕が着目したデータはユーザーのアクセスログです。ユーザーがどれくらいノマドを使っているのかが分かれば、そのユーザーがお部屋の問い合わせをするかどうかが分かるかもしれませんよね。
メソッド1
まずはユーザーのページのアクセスを1カウントとし、日毎に集計して使用しました。データの構造は以下の通りです。(ちなみに記事内のデータは参考データとなります)
24時間以内 | 2日目 | 3日目 |
---|---|---|
16 | 1 | 3 |
このユーザーは登録から24時間以内に16回どこかしらのページにアクセスしたといことになります。
登録から何日までのデータを使うかによって精度が変わってきますが、登録から近日中のデータだけを使うことにしました。ユーザーが問い合わせするかどうかが早期に分かれば、それだけ素早く何かしらのアクションを打つことが出来ます。登録して数日間はメッセージを送ったら見てくれるかもしれませんが、1週間経ったらもう手遅れかもしれません。
これはベーシックな分類のタスクなので、色んなモデルを使えます。今回のタスクのデータはアクセス数なので、リニアモデルで十分だろと思いました。アクセスが多ければ多いほど、問い合わせする可能性が高いというのがデータをざっと見た感覚で分かります。リニアモデルの代表ロジスティック回帰を使いました。
登録から3日間、1週間など色々試しましたが、精度は大体90%でした。
メソッド2
先ほどはユーザーがどのページにアクセスしたかを無視し、まとめて集計しただけでした。今度はどのページにアクセスしたかを考慮したらどうなるか試してみました。ユーザーログにはpathが保存されていましたが、そのままでは使えません。例えばIDが23456の部屋の詳細情報のページに飛んだ場合、pathはrooms/23456として保存されます。ただ、どの部屋のページに飛んだかは今回のタスクにおいてあまり重要ではありません。pathをこのまま使ってしまうと、特徴の数が膨大になって確実にオーバーフィットします。なので似たような性質の特徴はまとめる必要があります。
やり方は、pathを/で分けて、数字の部分を'number'というキーワードに変えるだけです。 pythonだと1行でいけます。
def replace_numbers(path):
return '/'.join(['number' if p.isdigit() else p for p in path.split('/')])
print(replace_numbers('/rooms/23456')) # => '/rooms/number'
これでpathをまとめた結果、70ほどに減りました。
データの構造は以下の通りです。実際は70カラムくらいあります。
/messages | rooms/number | /proposing_items |
---|---|---|
9 | 15 | 15 |
これでどのページにアクセスしたが考慮されるようになりましたが、いつアクセスしたかの情報は失われました。ただ登録から何日までのログを使うかを選択することは可能です。
登録から1週間のデータを使った時の精度が一番良く、95%でした。初日のデータだけでも92%ありました。
メソッド3
メソッド1はいつアクセスしたかを使い、メソッド2はどのページにアクセスしたかを使いました。自然な流れとしてはどちらの情報も使うことですよね!ただこれを普通にやろうとすると、横にそのまま並べるしかないので、pathが70あって3日間分使うとしたら210カラムになります。これでもやれなくはないんですが、こういう時はシーケンスモデルを使うと良いです。
データの構造は以下の通りです。それぞれのカラムを一つのシーケンスとしてLSTMに入れてみました。
24時間以内 | 2日目 | 3日目 | |
---|---|---|---|
/messages | 1 | 3 | 7 |
rooms/number | 3 | 6 | 2 |
/proposing_items | 2 | 5 | 2 |
1週間のデータでは、精度が96%に上がりました!しかも初日のデータだけを6時間ずつに割って試したら95%だったので、92%に比べて大幅な向上です! 登録から24時間で、そのユーザーが問い合わせるかどうかがかなりの高確率で分かるようになりました。
問い合わせ→内見
問い合わせしたユーザーが内見するかどうかを予測するには、そのユーザーがどれくらい問い合わせしたか、そしてその中でどれくらいのお部屋が空室なのかが最も重要だと考えました。実際空室のお部屋が一つもなければ内見に行けないわけですからね。
これが本当に重要なデータかどうかを検証するのは割と簡単です。ユーザー毎に問い合わせ数と空室の総計を出して、内見してないユーザーと内見したユーザーに分けます。それぞれ中央値を取って比較すればどれくらい違うか分かります。平均を使ってしまうと外れ値にかなり影響を受けるので、中央値の方が適切です。
案の定、問い合わせ数、空室共にハッキリと違いがあったので、データとして使えることが分かりました。
メソッド1
まずは、初めて問い合わせしてから何日か後までの問い合わせ数と空室数を日毎に集計して使用しました。データはこんな感じです。
24時間以内 | 2日目 | 3日目 | |
---|---|---|---|
問い合わせ | 1 | 3 | 18 |
空室 | 1 | 0 | 8 |
このユーザーは初めて問い合わせしたお部屋は空室で、その翌日また3件問い合わせしたところ一つも空いてなかったということになります。
またLSTMを使用してみました。すると問い合わせ初日から1週間のデータで85%という結果でした。うーん微妙ですね。
メソッド2
次は初めて問い合わせしてから何日か後までの問い合わせ数と空室数をまとめて集計し使用しました。先ほどの例を使うとこうなります。
問い合わせ | 空室 |
---|---|
22 | 9 |
今度はロジスティック回帰を使いました。結果精度は90%に上がりました。ということはいつ問い合わせたかはあまり関係ないということになります。
メソッド3
最後に、初めて問い合わせしてから何日か後までの空室数だけをまとめて集計し使用しました。特徴が一つだけのデータというのも味気ないですが、興味本位でやってみました。すると精度は変わらず90%でした!
考えられる理由としては、空室数は問い合わせ数に依存しているので、空室数にある程度問合せ数のデータも含まれていることになります。このようなデータがある場合は省いてあげるとモデルがシンプルになるのでオーバーフィットを避けることが出来、更に人に説明し易いという利点があります。「初めて問合せてから一週間以内の空室数が〇〇件以上のユーザーは、90%の確率で内見する」と言えば、誰でも理解出来ますよね。
登録→問い合わせフェーズの分析では複雑なモデルの方が精度が良かったですが、今回は全く逆の結果となりました。
90%止まりになってしまった理由は幾つかあります。まず、登録→問合せよりもファネルの奥になるので、対象ユーザーがあまり多くないです。もう一つは、空室数だけではやはり不十分です。実際空室が1件だけでも内見に行く人はいますし、10件以上あっても行かない人はいます。アクセスログなど色んなデータを加えて試してみる予定です。
Step4. 結果のアウトプット
モデルを学習させたら、それを何らかの形でアウトプットする必要があります。特徴選択だったら、何のデータが重要だったかを報告し、それを元に人が何らかのアクションを起こす事になります。分類の場合はAPIを作って既存のサービスに使うことが多いと思います。
今回は社内で結果を報告し、更にAPIも作ろうかなと検討しています。
まとめ
データサイエンスって機械学習を勉強していた頃はあまり興味がありませんでした。AIの方が派手で面白そうだったので、そっちの勉強ばかりしていたんですね。でも実際やってみるとめちゃくちゃ面白いです。クリエイティブに問題解決が出来るのでやりがいがあると思います。"The Sexiest Job of the 21st Century"と言われるのも無理はないかもしれません。
イタンジでは入社してすぐにこんな面白い仕事が出来ますよ!まだまだクレイジーなエンジニアを募集してますので、興味のある方は是非オフィスに遊びにいらして下さい!