まだ誰もやってなさそうだったのでやってみました。
オリジナルのリポジトリ The-Japan-DataScientist-Society/100knocks-preprocess をフォークして ruby-pycall
ブランチを追加しています。
GitHub でノートブックを閲覧したい場合はこちら:
https://github.com/sonota88/100knocks-preprocess/blob/ruby-pycall/docker/work/answer/ans_preprocess_knock_Ruby_PyCall.ipynb
解答例が複数ある場合など一部TODOにしている箇所がありますが、100問全部動かすことができました(私は Python版からコピペして書き換えただけなので、これは PyCall.rb がすごい! という話です)。
一応筆者について書いておくと、データサイエンスに関しては入門者レベルです。データフレームという概念は一応知ってるとか、Jupyter Notebook を触ったことはあるが日常的に使っているわけではない、という感じの人です。Python, Pandas, NumPy のいずれにも詳しくありません。
ちなみに Ruby + RedAmber 版は @heronshoes さんが作成中とのことです。
動かし方
リポジトリとブランチが違う以外はオリジナルのデータサイエンス100本ノック(構造化データ加工編)の README で書かれている手順と同じです。
git clone --branch ruby-pycall https://github.com/sonota88/100knocks-preprocess.git
cd 100knocks-preprocess
docker compose up -d --build --wait
docker compose up
が完了するのを待ってからブラウザで http://127.0.0.1:8888/ を開きます。
左のメニューから /work/answer/ans_preprocess_knock_Ruby_PyCall.ipynb
を選択してノートブックを開きます。
左側に Table of Contents を表示させておくと各問題に移動したいときに便利です。
メモ
Ruby 向けのカスタマイズ
- Python 版の Dockerfile をコピー+修正して Ruby 用の Dockerfile-ruby を用意する
- docker-compose.yml を修正して Dockerfile-ruby に切り替える
やったのはこれだけですね。ここはほとんど手間がかかっていません。
RubyData プロジェクトでメンテナンスされている rubydata/datascience-notebook
という Docker イメージがありまして、
これをベースイメージとして使うのがポイントです。自前でカスタマイズする必要がほとんどなく、たいへん助かりました。このイメージは便利なのでどんどん使わせてもらいましょう!(← この記事で一番強調したいのはここ)
Python版の Dockerfile との差分はこんな感じ。
--- Dockerfile 2023-05-06 12:13:18.226946937 +0900
+++ Dockerfile-ruby 2023-05-06 12:13:18.242946463 +0900
@@ -1,5 +1,6 @@
-FROM jupyter/datascience-notebook:python-3.10.8
-#FROM jupyter/datascience-notebook:d53a302fbcd0
+# 2023-02-03
+FROM rubydata/datascience-notebook:24a7f04dfc46
+
USER root
ENV DEBCONF_NOWARNINGS yes
@@ -29,4 +30,6 @@
&& Rscript -e 'pak::repo_add(CRAN = "RSPM@2022-12-16"); pak::pak(c("DBI", "RPostgreSQL", "themis"))' \
&& rm -rf Pipfile* /tmp/* /var/tmp/*
+RUN pip install tabulate
+
HEALTHCHECK --interval=5s --retries=20 CMD ["curl", "-s", "-S", "-o", "/dev/null", "http://localhost:8888"]
ほぼベースイメージの差し替えだけで済んでいます。
DataFrame#query
Python版の解答例では DataFrame#query を使っている箇所がいくつかあるのですが、pandas.rb ではエラーになります(2023-05-13 時点)。そこで、次のように DataFrame#[] を使う方法で愚直に書き換えました。
# P-004 Python版の解答例1
# df_receipt[['sales_ymd', 'customer_id', 'product_cd', 'amount']] \
# .query('customer_id == "CS018205000001" & amount >= 1000')
df_receipt[['sales_ymd', 'customer_id', 'product_cd', 'amount']] \
[(df_receipt['customer_id'] == "CS018205000001") & (df_receipt['amount'] >= 1000)]
PyCall.rb + Pandas: DataFrame#query の代わりにS式っぽく書けないか試してみた という別記事で書いたように他の対策もありますが、今回は素朴に DataFrame#[] を使うだけにしました。なるべく素のまま書く方針です。
参考
- mrkn/pycall.rb: Calling Python functions from the Ruby language
- Ruby-Pythonブリッジライブラリ「PyCall」を使ってRubyでデータ分析をしよう! (1/3)|CodeZine(コードジン)
-
workshop-materials/users_guide.md at master · RubyData/workshop-materials · GitHub
- IRuby Notebook 入門用テキスト
- PyCall Ruby版 Tips - Qiita
この記事を読んだ人は(ひょっとしたら)こちらも読んでいます