0. はじめに
0.1 あいさつ
ジーズアカデミーAdvent Calendar 2021の2日目の記事を担当する髙橋(@philosophy_note)です。
4月〜11月までTOKYO LABコースに所属しておりました。
11月4日に開催されたGGAにも登壇いたしました。
現在は主にデータエンジニアを目指して就職活動をしております。
2022年2月よりエンジニアとして働き始めました!
ちなみにGGAでは主に**機械学習モデルの開発過程と競馬の回収率の過程(1日9%を記録したこともあります笑)をとにかく熱く語り、**次のような感想をいただきました。
「この人変態だ笑」
「いい意味で狂ってる」
「完璧に狂ってくれたので安心しました」
0.2 開発アプリ概要
アプリ名:競馬予想AI×SNS 「Horecast」
機能一覧
AI予想表示機能
データ収集から機械学習モデル構築に至るまで、私が0から一気通貫して開発した競馬予想モデルの予想内容を見ることができます。
開催情報・出走馬の一覧はもちろん、レース結果に加えて購入を推奨した馬券の的中結果・払戻金も確認することができます。
また、データは10分ごとに更新されます。
ダッシュボード(2021年12月21日現在削除)
機械学習モデル開発時に使用した2010年から2021年の競馬レースデータを見ることができます。
競馬場とレース形式(芝・ダート・障害)と距離で検索すると、次の図のようなグラフが表示されます。
具体的には枠順・騎手・調教師・種牡馬ごとに勝率・連対率・複勝率を比較することができます。
項目を追加すると直ちにグラフも追加されます。
予想共有・検索機能
他のユーザーの予想を見ることができます。検索機能も備えています。
自分の予想結果を投稿することもでき、レース終了後に予想の反省を投稿し、次回以降の予想の参考とすることができます。
プロダクト設計仕様
- HTML5
- CSS3
- Bootstrap5
- Javascript
- jQuery3.6.0
- Python 3.8.8
- Django 3.2
- Dash 2.0.0
- PostgreSQL12.4
(モデル部分)
- Python 3.8.8
- Beautiful Soup4 4.9.3
- pandas 1.3.2
- Numpy 1.19.2
- seaborn 0.11.2
- matplotlib 3.4.2
- LightGBM 3.1.1
- OPTUNA 2.6.0
- scikit-learn 0.24.2
(インフラ・開発ツール)
- Heroku(Time Scheduler)
- AWS(Glue / S3)
- pgAdmin(DB管理ツール)
- Notion(タスク管理)
- Github(コード管理)
- Anaconda(Python実行環境)
- JupyterLab(Python実行環境)
0.3 執筆目的・対象読者・記事構成
記事の目的は機械学習モデルを用いたオリジナルアプリの開発経験の共有です。
開発手順や難所の突破方法、反省点や使用したツールなどを記載しています。
対象読者としては、
- 今後オリジナルアプリを開発するG's ACADEMY現役生
- G's ACADEMYに興味を持っており、どんな人がいて、どんな物を開発しているのか気になる方
- G's ACADEMYに限らず何らかの目的で個人開発しようとしている方
- AIってどうやって作るのか興味がある方
- 競馬が好きな方
上記のいずれかに該当するのであれば是非読んでいただきたいと思います。
記事の内容について説明します。
「1.自己紹介」ではG's ACADEMYに入学した経緯と過ごし方そして今回のアプリの開発理由について記載しています。
「2.開発ロードマップ」〜「5.アプリ制作」で開発過程について記載しています。
「6.難所とその解決方法」では開発で詰まったところとその解決方法についてまとめています。
「7.反省点など」は開発後に後悔している内容を記載しています。
「8.さいごに」はまとめです。
「おまけ」は開発で使用したツールや学習教材などを記載しています。
1. 自己紹介
1.1 略歴(〜ジーズ入学前)
大学卒業後5年間都内の公的機関で働いておりました。
大学時代にデータ分析をしていた経験からAIに興味を持ち始めました。
AIを学ぶには自分で作ることが一番良いだろうと考え、
趣味である競馬予想の知識を元に実際にAIを作り始めました。
やがてプログラミングの楽しさに気づき、仕事を退職し、G's ACADEMYに入学しました。
なお、入学時にはPythonの知識は多少ありましたが、いわゆる"WEB系"の知識はゼロでした。
(例えばPythonでWebアプリケーションを作れることはジーズ入学後に知りました)
1.2 ジーズでの日々
G's ACADEMY LABコースは最初の2.5ヶ月間でJavascriptやPHPを学び、最低でも毎週1つWEBアプリケーションを作成するカリキュラムでした。
私が作成したものを一部抜粋してご紹介します。
- Djangoの存在を知ってから2週間、HTML・CSSを学んでから10日間、Javascriptを学んでから1週間。
『じゃんけんアプリを作る』という課題でDjangoを使用した読書レビュー掲示板を作成 - 『チャットアプリを作る』という課題をほぼ無視してPythonでTwitterAPIを操作して文章を取得し、
Janomeで形態素解析した単語をマルコフ連鎖で適当にくっつけたり、WordCloudを作成 - JavascriptハッカソンでDjangoを利用したWEBアプリケーションを作成し2位入賞
- データベースを使えるようになったことが嬉しすぎて、
とりあえずPythonでGAFAの株価5年分を取得して全てデータベースに格納したはいいが
データの数が多すぎて何もできなくなる -
PHPハッカソンではとうとうHTML・CSS・Javascript・PHPを一切使わずPythonだけで
WEBアプリケーションを作成
次のリンクから作成物の一覧を確認できます。
また、一部開発物についてはG’s ACADEMY 学校長である山崎先生が作成した次の動画で説明もしています。
そして、後半期間でオリジナルアプリを開発します。
私は**『AIを自分で作りたい』**という思いを実現するため、
入学前から取り組んでいた競馬予想モデルをアプリケーション化することにしました。
1.3 競馬予想AI×SNSアプリの開発理由
さて、G's ACADEMYでは**「why me?」**という問いかけが重要視されています。
「why me?」を言い換えると「なぜあなたがそれをやるのか、作るのか?」という問いかけになります。
私の答えは次です。
AIの中身が知りたい。知るためには作ることが一番。だから作る。
…これだけです。
G'sの偉大な先輩方と比較したらなんと些細なことか。
まあwhy meは比較しようもないし、好奇心持ったからには思いっきりやろう
そう自分にいつも言い聞かせていました。
2. 開発ロードマップ
2.1 開発工程
開発工程は次の通りです。
時期 | 工程 |
---|---|
8月上旬 | 機械学習モデル作成開始・追加データ準備 |
8月中旬 | 機械学習モデル作成完了(以後毎週末レースを予測し、修正を繰り返す) |
8月下旬〜9月上旬 | アプリ要件定義開始・技術選定 |
9月中旬 | 出馬表及び予想表示機能開発・仮デプロイ |
9月下旬 | 要件定義終了・結果表示機能開発 |
10月上旬 | ダッシュボード・予想共有機能開発 |
10月10日 | 完成・提出(以降、GGAまでエラー・バグ対応とデザイン修正) |
振り返るとタイトなスケジュールだったと思います。 | |
最終的な要件定義から完成まで2,3週間で一気に仕上げました。 | |
ユーザーテストを行いたい場合はもっと早めに開発しないと絶対に間に合いません。 |
2.2 優先順位
次のようにレベルを決めていました。
開発レベル | 内容 |
---|---|
レベル1 | Django内部で予測して結果を返す |
レベル2 | 自動でデータを取得する(ここまでがコア機能) |
レベル3 | 馬券の的中結果を表示する |
レベル4 | ダッシュボード |
レベル5 | 予想共有機能 |
今後開発される方は次の言葉を覚えていただきたいです。
とにかくコア機能を早期に完成させてデプロイする
レベル1と2がこのアプリのコア機能に当たる部分でした。
従って要件定義やワイヤーフレームの作成と並行して機械学習モデルとその結果を表示する部分の開発を真っ先に行いました。
また、最低限の機能が完成したところですぐにサーバーにデプロイしました。
今回の場合も出馬表のスクレイピング機能をHerokuにデプロイしたところ、
Herokuのリクエストタイムアウトの関係で1件も取得できないことが判明しました。
また、ダッシュボードをデプロイしたところ、メモリ超過でサーバーが強制的にシャットダウンしました。
提出3日前のことです。
早めにデプロイしましょう。
3. 要件定義
実は当初はGGAに出場することは考えていませんでした。
プロダクトの機能も次のように自分だけが使うことが考えるように設計していました。
- 毎週末の競馬予想をする競馬予想モデルを作成する
- 予想に必要なデータは自動取得する(結果の取得は行わない)
- DjangoでWEBアプリケーション化する(モデルの結果を表示するだけ)
3.1 ユーザーストーリー
そこでメンターさんからユーザストーリーを作成することを勧められました。
ユーザーストーリーについては次の記事などで確認してください。
メンターさんからは『これではただ機能の羅列ですね』と言われました。
『まず考えるべきなのはバックボーンです』が次の言葉でした。
つまり『ユーザーはどういう考えを持ってアプリを利用(今回の場合は競馬予想)するのか』をまず考えます。
次にユーザーの利用時の考えを時系列順に考えます。
その考えを具体的な行動に落とし込みます。これがナラティブフローになります。
最終的にユーザーの動きを想定し、優先順位をつけてどの機能を実装するかを決めます。
3.2 ワイヤーフレーム作成(できず)
機能が固まったところでワイヤーフレームを作成します。
最初の自分用のプロダクトを作成した際には次のNoteを参考にしながらFigmaで作成しました。
ただしここで重大なミスをします。
上述したように最終的なユーザーストーリーが完成したのが、提出期限の2週間ほど前のためワイヤーフレームを再度作る時間がなく、
ノートに手書きで簡単なイメージを作成し、細かいところは作りながら修正すればいいという考えで先に進めました。
これが次の工程に響くことになります。
ちなみに当初作成していたワイヤーフレームの一部が次になります。
完成品と全く異なります。
3.3 ER図作成
ワイヤーフレームが固まった段階でER図を作成します。
最初は画面イメージとER図の関係性が今ひとつ掴めていませんでしたが、
画面イメージなしにER図を作ると後々苦労します。
具体的には、データベースにどのような値が格納されるのか、
どのタイミングでどのデータを取得するのかは画面を作る段階を踏んでから先に進まないと
正確なER図を作ることができません。
私の場合予想表示機能についてはワイヤーフレームを作成していたので特に問題なく進めることができました。
しかしながら、予想共有機能の画面推移をまともに設計していなかったので、
作ったテーブルを壊し、再度設定からやり直すことを何回もしてしまいました。
せめて手書きで画面表示を考えておけばよかった…
同じく当初作成していたER図です。最終形はこの倍のテーブルを作成しました。
3.4 技術選定・アーキテクチャ
ジーズ生はここで悩む方は多いと思います。
私の同期でVueやReactを学習した人はNuxt.jsやNext.jsでフロント中心で開発し、DBはFirebaseを使うケースが多数でした。
その一方でLaravelで本格的なWEBアプリケーションを作成する人もいました。
私の場合は
・FastAPIでAPIサーバーを構築し、別にWEBサーバーを構築する
・Djangoの内部にモデルを組み込み全て完結させる
の2択で迷いました。
最終的には開発経験があることやドキュメントの充実さから後者を選択しました。
Dockerでコンテナを作ることも検討しましたが、あくまで個人開発という観点から見送りました。
(ただモダンな技術で開発することを重視するのであれば次の本のようにDocker×FastAPIが良かったのかな…)
DBに関してはDjangoとセットで使用されている事例が多いという理由でPostgreSQLを採用しました。
モデル部分とバックエンドに時間を割きたかったのでフロントエンドはBootstrapとjQueryで簡潔に済ませることにしました。
4. モデル制作
4.1 データ収集
競馬情報サイトより分析に必要なデータをスクレイピングで取得しました。
取得したデータは次の通りです。
・レースデータ(2011~2020の10年分の中央競馬で開催された全レースの結果)
・競走馬データ(上のレースに出走した競走馬のレース結果のデータ、血統も含む)
・騎手データ(2011~2020の10年分の騎手の成績・獲得賞金)
・調教師データ(2011~2020の10年分の調教師の成績・獲得賞金)
またレースの予想対象となる出馬表についても同じくスクレイピングで入手しました。
スクレイピングはPandasとBeautifulsoupで実装しました。
単勝オッズなどリアルタイムで変化するデータに対してはSeleniumで取得することも考えましたが、
使用しなくても予想はできるので採用は見送りました。
(もう一つ見送った理由としてブラウザを直接操作するため取得に時間がかかるという点もありましたが、
今考えてみると高々36レースの出馬表の取得にそこまで時間はかからないので採用してもよかったのかもしれません)
4.2 データ前処理
取得したデータをPandasやNumpyを使用してクレンジングします。
次以降の行程次第で何度もやり直すことになります。地味な作業ですが大切な行程です。
4.3 EDA(探索的データ解析)
取得したデータについてデータ型や値の分布、欠損値、外れ値をチェックします。
また、目的変数と各変数の相関や関係性を把握します。
その後Yes/Noで答えられる仮説を立てながらデータを分析していきます。
立てた仮説は例えば次のようなものです。
- 斤量が前走と比べて小さくなると着順が良くなる
- コースの距離が前走と比べて短くなると着順が良くなる
- ダートレースはパワーを要するため馬体重が重い方が着順が良くなる
ちなみに仮説は自分の経験から立てたものあれば、競馬予想の本を買ってそこに書いてある内容を再検証したものもあります。
4.4 特徴量エンジニアリング
3.3と同時並行で行っていました。
カテゴリ変数の作成や順位変換、テーブル結合といった手法を用いて
EDAで検証した仮説をモデルに入力できるように変数を変換します。
4.5 モデル構築・性能評価
使用するモデルは使いやすさと精度の高さからGBDTを採用しました。
使用したライブラリはLightgbmになります。
パラメータチューニングはグリッドサーチを当初採用していましたが、
手数がかかるので、ベイズ最適化を行うフレームワークであるOptunaで求めた値でモデルを構築しました。評価指標はAUCを採用し、クロスバリデーションで評価を行っています。
5. アプリ制作
5.1 予想表示機能
一言で予想表示機能と言っていますが、予想だけでなく結果や払戻金も取得して表示しています。
仮デプロイで判明したスクレイピングできないという問題はHeroku Schedulerでの定期実行で解決しました。
5.2 ダッシュボード機能
インタラクティブなグラフ(入力値に応じてすぐに変化するグラフ)を表現するため、
PlotlyDashを採用しました。
使用するデータはAmazon S3に保存し、AWS Glueを使用してcsv形式から軽量なParquet形式に変換しています。
5.3 予想共有掲示板機能
基本的なCRUD操作が中心ですが、
DjangoのModelChoiceFieldを利用してレースを選択すると、該当するレースの出走馬が選択肢として自動的に表現されるように
設定しました。
views.pyでmodel.pyからform.pyに値を受け渡す箇所で苦労しました。
6.問題の解決方法
開発中色々困難がありましたが、技術面は全て一人で解決しました。(後述しますがこれは反省ポイントです。)
心がけていたのは検索だけでなく公式ドキュメントを読むようにするです。
エラーなどが発生した場合は検索すれば色々な忘備録や質問への返答が出てきます。
これだけで解決する場合もありますが、なるべく公式ドキュメントで確認することを心がけていました。
以前は対応できていましたが、バージョンが変わったことで今ではその方法が通用しないことがあります。
例えばPandasのデータフレームをPostgreSQLでDBに保存する際にpangresというライブラリを用いました。
この時ネットの記事を参考にしたのですが、記事通りにしても上手くいきません。
仕方がないので公式ドキュメントを参照したところ、バージョンが変更になり、命名規則などがかなり変わっていました。
他にもPlotlyDashやS3は使用例が少なかったり、バージョンの移り変わりが激しかったので公式ドキュメントが頼りになりました。
7.反省点
7.1 UI/UXにこだわることができなかった
ワイヤーフレームの仕上げが甘かったことは上述した通りです。
加えて本来であればユーザーストーリーとワーヤーフレームの間にどういうデザインにすれば
ユーザーは使いやすくなるかと言ったUI/UXについて考えるステップを飛ばしてしまいました。
対応策として、今回は次の既存の2つのサービスを参考にしてながら作成しました。
何らかのサービスを作成する際には類似サービスを必ず研究すべきです。
ユーザーは既存のサービスのUXを学習しているので、
それに合わせる形で作成しないとユーザーとのコミュニケーションが上手くいきません。
その点もある程度考慮して開発したのですが、
ユーザーが本当に使いやすいデザインかと言われると肯定はできません。
まだ改良の余地はあると思います。
(例えばレース詳細画面はタブ形式で別のレース切り替えた方が使いやすいと思っています)
7.2 技術面を完全な独学で進めた
メンターの方には要件定義やアーキテクチャなど様々な点でお世話になりました。
一方で技術面は完全に独学で進めました。
幸いなことに検索すれば知りたい情報は出てくるので自力で完成はできました。
ただ、独学で十分条件は満たせないと思います。
例えば技術選定は何がベストプラクティスかわからないまま進んでしまいました。
コードの書き方もとりあえず動けばOKという考え方で可読性などの面を考慮していません。
就職を見据えると技術面に関して相談できる場を用意した方がよかったのかなあと思っています。
7.3 モチベーションを保つ工夫をするべきだった
開発期間は約2ヶ月。朝から晩までコミットできる!
…頭の中では理解できるんです。頭の中では。
特に最後の方は身体と心がついてきませんでした。
いくら自分が熱量を持って取り組めることだとしても2ヶ月間一つのことに集中することは思った以上に大変でした。
今回の開発は一人でやる場合『まあこれていいだろう』と妥協してしまいがちになり、
それで後々後悔することがありました。
スケジュール・タスク管理をこまめに行い、日報を記入して進捗に遅れがないか振り返ることは継続していましたが、
それでも不十分でした。
自分を引き締めたり、逆に気を緩めたり、あるいは別のことに没頭するといったモチベーションの管理に意識的に取り組むべきでした。
8. 最後に
長い記事を読んでいただき本当にありがとうございました!
記事を書こうと思ったきっかけはG's ACADEMYで教わったナレッジの共有の重要性にあります。
学校の説明会や事業対策講座でもこの点を何度も学びました。
私の経験が誰かにとって有益なものとなり、私の想像を超えた新しいプロダクトやサービスの開発に結びつけば嬉しい。
その一心で書きました。技術的な話は極力控え、多くの人が直面するであろう悩みを中心的に書いたつもりです。
ただ、私自身が色々な意味で外れ値だと自負しているので、参考にならなかったらごめんなさい笑
参考になったという方がおりましたら、是非LGTM、ストック、Twitterでのシェアお願いします!
してくれたら泣いて喜びます笑!
また、ご質問などありましたら、TwitterでDMいただけますと幸いです!
特にG's生であれば大歓迎です!!
Twitter: https://twitter.com/philosophy_note
おまけ
使用したツール・学習教材などについて記載します。
ツール
Notion
スケジュール管理・タスク管理・イメージ共有・参考記事のデータベース・日報の記入、全てこなす最強ツールです。
特にNotion Web Clipperはクリック一つで参考記事のデータベースが簡単にできるので、大変重宝しました。
Miro
Miroを見ろ
ユーザーストーリーやアーキテクチャの作成の際にメンターさんと共有するために使用していました。
オンラインホワイトボードです。
Figma
ワイヤーフレーム作成時に使用。
色々できますが、慣れるまで時間がかかります。
LaravelDB.com
名前にもあるように本来はER図を作成してLaravelのMigrationファイルまで作成してくれるサービスです。
ただ、簡単にデータ型やプライマリーキーの設定、リレーションシップの構築ができるため、ER図だけの作成用として使っていました。
Pixabay
使用したフリー画像は全てここからダウンロードしました。
Material Design for Bootstrap
マテリアルデザインが簡単に作成できるBootstrapです。
見やすくカッコいいデザインでフロントエンドを作成することができます。
Shopify Hatchful
制約はありますがイメージに従うだけで
ロゴやファビコンを自動作成してくれます。
canva
自分である程度自由に作成したい場合はこちら。
自分で作るだけではなく、色々なテンプレートを見ることができるのでデザインの参考になります。
ColorSpace
メインカラーとしたい色の色コードを入力するだけで
相性のいい色のセットを10種類ほど表示してくれます。
ColorZilla(GoogleChrome拡張機能)
『このサイトの色何使っているんだろう?』というときに使える拡張機能。
知りたい部分をクリックするだけで色コードがわかります。
DeepL翻訳
翻訳ができます。頼りすぎ厳禁。
学習教材
Udemy
オンライン動画学習教材が大量に提供されています。
Djangoについては次の教材が大いに参考になりました。
Pythonでのデータ分析は次の動画から始めました。
ちょっと古くなってしまったので、今始めるなら次の動画が良いと思います。
(ただし機械学習がない)
Pythonではじめる機械学習
スクール入学前にPythonでの機械学習実装を勉強するために購入した本です。
これ一冊で基本的なモデル作成などの知識を学ぶことができます。
Kaggleで勝つデータ分析の技術
書名の通りKaggle対策本ですが、特徴量の作り方やモデルの評価方法が
実装コードとともに記載されていて非常に勉強になりました。