はじめに
いつも心は虹色に! nikkieです。
「夏だなー。思いっきり開発したいなー」ということで、合宿に参加してきました。
合宿の概要
Python mini hack-a-thon 夏山合宿 2018 - connpass
毎年夏、冬に行っている、Python mini Hack-a-thonの合宿バージョンです。
部屋にこもって開発するも良し、食堂でボードゲームするもよし、高原を散歩するもよし、周辺でゴルフや釣りをするも良し、というお気楽な会(Python関連の知り合いとの夏山合宿)です。
半年くらい前から顔を出しているpyhackの合宿ということで、3泊4日フルで飛び込んできました。
申し込んだ時点では、モザイクアートなどの個人のプロジェクトを進める時間にしようと考えていましたが、
最近のもくもくの傾向に従ってか、業務関係のもくもくとなりました。
もくもくの目標
以下の構成のアプリケーションをローカルで動かす。
- PySparkで作成した協調フィルタリングのモデル
- 協調フィルタリングのモデルを読み込み、ユーザへのおすすめアイテムを返すAPI(flask)
- APIを呼び出すアプリケーション(Ruby on Rails)
とあるテキスト(チュートリアル)をもとに進めています。
触ったもの
- ぐるなびAPI(レストラン検索)
- Docker
- ipython-sql
- 協調フィルタリング(PySpark)
- flask
- Ruby on Rails
ぐるなびAPI
レストラン検索APIのサンプルコードをもとに
Python3系でrequests
を使ってAPIリクエストを実装しました。
デフォルトでは10件ずつ返すので、21件ヒットしたときは
- 最初の10件
- 次の10件
- 1件
というように取得できます。
10件返すときと1件返すときとでJSONの形式が異なることが判明し、実装でカバーするのはなかなか骨が折れました。
#pyhack
— nikkie (@ftnext) 2018年7月13日
requests使って、ぐるなびレストラン検索APIを叩く
返ってくるJSONの'rest'の値が問題。
・レストランが1件返ってくるとき1件の{}が返る
・複数件返ってくるとき[{}, {}, ...]という形で返る
→1件のときは[{}]として返すほうがきれいでは?https://t.co/98gql6TQfR
Docker
今回の合宿ではめちゃくちゃ恩恵にあずかりました。Dockerさん、本当にかたじけない。
PySparkやRailsなど幅広く触れたのは、Dockerで環境構築が簡略化されたためと考えています。
- dbコンテナ(mysql)へのデータ永続化は、コンテナ側の
/var/lib/mysql
をマウント- 情報源: docker-composeでデータベースコンテナを立てるときのTips
- ターミナルのメッセージ:
Creating volume "recommend_tutorial_app_db-volume" with default driver
-> Dockerのvolumeについて情報収集すれば理解できそう
ipython-sql
jupyter notebookからSQLが使えます! 便利!!
参考: Jupyter Notebook(Anaconda/Windows)からMySQLに接続する(Python)
_が変数として活躍します。
最後の結果はアンダーバー(アンダースコア)「_」変数に格納されるため、次のセルで「df = _.DataFrame()」などと呼び出すと、(以下略。上記参考記事より引用)
SQLの実行結果をnotebookとして共有できるのがいいよねという話にもなりました。
協調フィルタリング(PySpark)
Azure Machine Learning Studioでベンダー用意の実装は使ったことがありましたが、PySparkを使うという手もあるんですね。
参考: PySparkで協調フィルタリング
行列分解(Matrix Factorization)を使っているようです。
flaskアプリケーションをPySparkが使える環境で動かすことで、
協調フィルタリングのモデルを読み込み、予測を取得ということができました。
(flaskアプリからおすすめするアイテムのIDが返せる)
Ruby on Rails
Rails Tutorial 8章も眺めながら、ログイン機能の実装を進めていきました。
ログインしたユーザについてflaskのAPIを使ってレコメンドをする部分を実装しました。
今回のもくもくでは、レコメンドが主機能のアプリを開発したわけではなく、
既存システムにレコメンド機能を組み込むにはこういう作業をするというところが掴めたかなと思います。
IDの扱いの問題
ここまでの作業は2日目の夜には終わったのですが、IDの扱いのズレに気づきました。
3日目にはIDのズレを解消するため、チュートリアルをやり直していました。
アイテムのIDはモデルでもDBでも0から始まるように合わせ、ユーザのIDは読み替えるという方針を取りました。1
2周め: Railsアプリケーション作り直し
間を開けずに2周めということでだいぶ苦しかったですが、なんとかやりきりました。。
- DBのアイテムIDを0から始まるように変更
- マイグレーションファイルを手動で作成し、0から始まるIDを
my_id
として用意しました。(Railsが自動でつくるid
は使わないように設定) - 参考: Rails テーブル(モデル)を新規作成する
- マイグレーションファイルを手動で作成し、0から始まるIDを
- ログイン処理の動きを少し理解
- 作り直す前はブラックボックスだったのですが、Rails Tutorial 8章メインで進めたことで何をやっているかわかってきました。
- ログインフォームの画面は
Sessions#new
が出す (ログインに失敗したときも呼ばれる) - ログインフォームに入力しsubmitした(POSTで通信した)あと、
Sessions#create
が呼ばれる - ログインに成功したら
Users#show
が画面を出すように設定 - ログアウト処理は
Sessions#destroy
による
- ログインフォームの画面は
- 作り直す前はブラックボックスだったのですが、Rails Tutorial 8章メインで進めたことで何をやっているかわかってきました。
感想
いやーー、はかどりました。pyhackのもくもく会が連日開催というような感じでしたねー。
暑い日もありましたが、都内に比べたら十分涼しかったです。
開発しかやることがない状況と非日常感で、目標部分は2日で完了まで持っていけました。(問題への対応でやり直しましたが。。)
マウンテンパパさんの食事は豪華でとてもおいしく、開発の合間でリフレッシュできました。
冬は寒そうですが、行ってみたいなと思います。#pyhack
— nikkie (@ftnext) 2018年7月13日
晩ごはん豪華でした。
大変おいしかったです。 pic.twitter.com/AVhUk1q62G
マウンテンパパの皆さま、幹事・参加者の皆さま、どうもありがとうございました!
おまけ
サマー・ウォーズ巡礼もちょっとできたので満足です!
余は満足じゃー(上田城近くの観光案内所にて)
— nikkie (@ftnext) 2018年7月16日
細田監督直筆表紙らしい pic.twitter.com/kEWOF3FoDx