nikkie-ftnextの日記

イベントレポートや読書メモを発信

イベントレポート | Python mini hack-a-thon 夏山合宿 2018 レコメンドアプリケーションをもくもく #pyhack

はじめに

いつも心は虹色に! nikkieです。
「夏だなー。思いっきり開発したいなー」ということで、合宿に参加してきました。

合宿の概要

Python mini hack-a-thon 夏山合宿 2018 - connpass

毎年夏、冬に行っている、Python mini Hack-a-thonの合宿バージョンです。
部屋にこもって開発するも良し、食堂でボードゲームするもよし、高原を散歩するもよし、周辺でゴルフや釣りをするも良し、というお気楽な会(Python関連の知り合いとの夏山合宿)です。

半年くらい前から顔を出しているpyhackの合宿ということで、3泊4日フルで飛び込んできました。
申し込んだ時点では、モザイクアートなどの個人のプロジェクトを進める時間にしようと考えていましたが、
最近のもくもくの傾向に従ってか、業務関係のもくもくとなりました。

もくもくの目標

以下の構成のアプリケーションをローカルで動かす。

とあるテキスト(チュートリアル)をもとに進めています。

触ったもの

ぐるなびAPI

レストラン検索APIのサンプルコードをもとに
Python3系でrequestsを使ってAPIリクエストを実装しました。

デフォルトでは10件ずつ返すので、21件ヒットしたときは

  1. 最初の10件
  2. 次の10件
  3. 1件

というように取得できます。
10件返すときと1件返すときとでJSONの形式が異なることが判明し、実装でカバーするのはなかなか骨が折れました。

Docker

今回の合宿ではめちゃくちゃ恩恵にあずかりました。Dockerさん、本当にかたじけない。
PySparkやRailsなど幅広く触れたのは、Dockerで環境構築が簡略化されたためと考えています。

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の扱いのズレに気づきました。

  • PySparkで作成した協調フィルタリングモデル: アイテムのID、ユーザのIDはどちらも 0 から始まる
  • Railsアプリが参照するDB: アイテムのID、ユーザのIDはどちらも 1 から始まる

3日目にはIDのズレを解消するため、チュートリアルをやり直していました。
アイテムのIDはモデルでもDBでも0から始まるように合わせ、ユーザのIDは読み替えるという方針を取りました。1

2周め: Railsアプリケーション作り直し

間を開けずに2周めということでだいぶ苦しかったですが、なんとかやりきりました。。

  • DBのアイテムIDを0から始まるように変更
  • ログイン処理の動きを少し理解
    • 作り直す前はブラックボックスだったのですが、Rails Tutorial 8章メインで進めたことで何をやっているかわかってきました。
      • ログインフォームの画面はSessions#newが出す (ログインに失敗したときも呼ばれる)
      • ログインフォームに入力しsubmitした(POSTで通信した)あと、Sessions#createが呼ばれる
      • ログインに成功したらUsers#showが画面を出すように設定
      • ログアウト処理はSessions#destroyによる

感想

いやーー、はかどりました。pyhackのもくもく会が連日開催というような感じでしたねー。
暑い日もありましたが、都内に比べたら十分涼しかったです。
開発しかやることがない状況と非日常感で、目標部分は2日で完了まで持っていけました。(問題への対応でやり直しましたが。。)
マウンテンパパさんの食事は豪華でとてもおいしく、開発の合間でリフレッシュできました。

冬は寒そうですが、行ってみたいなと思います。

マウンテンパパの皆さま、幹事・参加者の皆さま、どうもありがとうございました!

おまけ

サマー・ウォーズ巡礼もちょっとできたので満足です!


f:id:nikkie-ftnext:20180716173353j:plain


  1. PySparkのモデルでアイテムのID、ユーザのIDをどちらも1から始めるように修正するアプローチもあると思います。(工数は小さそう)