リクルート メンバーズブログ  あなたの生産性を向上させるJupyter notebook Tips

あなたの生産性を向上させるJupyter notebook Tips

このエントリは全9回を予定する18卒新人ブログリレーの第3回です.

はじめまして.今年度よりリクルートテクノロジーズに入社した河野 晋策です.
7月からQassチームにて検索ロジックの改善を行っています.

Qassチームは,検索基盤の運用や検索ロジックの改善を行っているチームです.
詳しくは以下の記事をご覧ください.

本記事の想定読者:普段Jupyter notebook・Jupyter Lab,Google Colaboratoryを使っている方,またこれから使おうと考えている方
本記事の概要:jupyter notebookの知見共有

はじめに

Jupyter notebookとは

Jupyter notebookの例 [5]より引用

 

近年,データの重要性が様々なところで説かれており,リクルートテクノロジーズでもデータ活用の取り組みが多く行われています[1, 2].
また,Jupyterを使用する人や,会社も年々増えています[3, 4].

Jupyterは,Pythonをはじめ,R,Julia,Ruby,Cなど40を越える言語[6]のREPLとして活用できるオープンソースのウェブアプリケーションです.
またnotebookは,プログラムとその実行結果(図や表などを含む),リッチテキストを含むデータ分析に特化した実行可能なドキュメントです.
弊チームでは多くのデータ活用事例で,このJupyter notebookを使用しており,分析から結果の共有まで広く利用しています.

検索組織である弊チームでは,リクルートの多種多様なサービスにおいて,クライアントとカスタマーの両者にとって最適な検索を実現すること目指しています.
そのために,ユーザが「どのようなコンテンツに興味を示したか」,「どのようなコンテンツにコンバージョンしたか」,また,「コンバージョンに至る導線はどうだったか」,「検索によって表示されたコンテンツの中で選ばれたのはどれだったか」などユーザの行動を分析しています.
このデータ分析によって得られた事実・仮説をもとに既存の検索アルゴリズムをチューニング,あるいは新規の検索アルゴリズムを開発し,日々検索のパフォーマンスを向上させています.
これらの業務にJupyter notebookを用いることで,分析がスムーズになり,さらに分析結果の共有を簡単に行うことができています.

また,最近では,Googleが提供しているColaboratoryを使用することで環境構築の手間なく簡単にデータ分析環境を手に入れることもでき,使用者が増えています.

本記事の内容

前述のようにJupyter notebookの使用者は増えていますが,ユーザがJupyter notebookを最大限活用できていないことを示唆する報告もあります[7, 8].
そこで本記事では,普段Jupyterを使っている方,また導入を考えている方を対象にJupyterを使った作業の生産性を向上するような業務内外で得た知見を提供できればと思います.

本稿の構成は以下の通りです.

1 notebookにおけるコードの再利用

Jupyter notebookにおいて,新しいnotebookを立ち上げた時,以前のnotebookからコードを再利用することが多々あるのではないでしょうか?
文献[7, 8]では,再利用のためのnotebookを作成しているユーザもいることが報告されています.

例えば以下のようなインポート文です.

分析のための時間を,コードを探してコピー&ペーストする時間に割くのは,非常に勿体無いと言えるでしょう.
この問題を解決する方法は主に2つあります.

1.1 Nbextensions[9]

1つ目は,jupyter_contrib_nbextensionsJupyter notebook snippets menuを使う方法です.

これにより,notebookのナビバーから登録済みのスニペットを瞬時に貼りつけることが可能です.

Snippets Menuの動作

 

1.1.1 Jupyter notebook snippets menuの使い方

jupyter_contrib_nbextensionsのインストールは以下で行います.

上記コードが正常終了し,jupyter_contrib_nbextensionsのインストールが完了すれば,Nbextensionsを使用することができます.

Jupyter notebookを再起動し, http://localhost:8888/tree#nbextensions_configurator にアクセスすれば,Nbextensionsの設定タブにアクセスできます.

Nbextensionsの設定タブ

 

まず,Snippets Menuの設定メニューで Include custom menu content parsed from JSON string below のボックスにチェックします.
次に JSON string parsed to define custom menus (only used if the option above is checked) にスニペットとして登録しておくコードをJSON形式で入力します.

Snippets Menuの設定

 

上記Gifでは以下のスニペットを入力しています.

1.2 IPythonのstartup機能

2つ目の方法は,IPythonのstartup機能 を使う方法です.

IPythonのstartup機能を使用することでnotebookの起動時に任意のPythonコードを実行することができます.
以下のGifを見るとnotebook起動時に numpymatlotlib を自動的にロードできているのがわかると思います.

 

IPython startup機能

 

 

1.2.1 startup機能使い方

startup機能を利用するためには,まず,ipythonコマンドでプロファイルを作成する必要があります.
notebook上から以下のコードを実行します.

00-import_list.ipy に書いたコードはnotebookの起動時に自動で実行されます.

ここでは,以下のコードを入力しています.

00-import_list.py の拡張子以外は命名規則を充たす任意の名前が使用可能です.
※ 拡張子は py でも良いですが,%matplotlib inline などのマジックコマンドを書く場合は,拡張子を ipy にしなければいけません.

また,他の方法でもnotebookの起動時にライブラリを読み込むことができます.

例えば, .ipython/profile_default/ipython_config.pyc.InteractiveShellApp.exec_lines に追記する方法です.

ここでは,コードの再利用という前提があるので,コードが複数行あることが想定されます.
その場合,c.InteractiveShellApp.exec_lines に追記する方法よりもファイルごとに管理可能な startup ファイルを作成する方法の方がより用途に合っているでしょう.

1.3 まとめ

notebookにおけるコードの再利用という問題に対して,ここでは2つの方法を紹介しました.
1つ目は,Jupyter notebook snippets menu を使う方法です.
2つ目は,ipythonのstartup機能 を使う方法です.

ipythonのstartup機能 は,notebookの起動時に設定ファイルの全てのコードを暗黙に実行してしまうので,毎回,使用確実なライブラリのみを書くべきでしょう.
Jupyter notebook snippets menu は,コード以外のテキストも登録することができるので,公開ライセンスの文言を登録しておくと便利かもしれません.

2 notebookのカラースキーム

読者の方々は普段どんなエディタを使っているでしょうか.
Visual Studio Codeでしょうか.それとも,Atom?,Vim
チーム内でも様々なエディタが使われています.
では,カラースキームはどうでしょうか.
私はmonokaiを愛用していますが,社内ではsolarizedICEBERGを使ったり,また自作したり,様々なカラースキームが使われています.

Jupyter notebookの場合はどうでしょう.
エディタのカラースキームを自分用に最適化している方は非常に多いです.
しかし,そのような方々でもJupyter notebookのカラースキームを変更している様子は滅多に見ません.

ここでは,Jupyter notebookのカスタムCSSを定義することでnotebookの見た目を自分好みに最適化する方法を紹介します.

monokai風 Jupyter notebookカラースキーム

 

notebookのカラースキームを変更する方法は主に3つあります.
本章では,notebookのカラースキームを変更する方法を示した後,notebookのCSSをどう変更すればいいのか,また,変更用のテンプレートを記載します.

2.1 custom.css

notebookのカラースキームを変更する方法の1つ目は,custom.cssを定義する方法です.

Jupyterは,HOMEディレクトリ以下の .jupyter に設定用フォルダがあります.
.jupyter フォルダ以下の customcustom.css を配置することでnotebook起動時に適用することができます.

しかしこの方法は,notebookの設定を変更してしまうため,個人に最適化しすぎた場合,他人にとって見づらくなり,また,再設定が手間になります.

2.2 IPython.display

notebookのカラースキームを変更する2つ目の方法は,notebookから IPython.display を用いる方法です.
この方法は,上記の問題を解決してくれます.

IPython.display は,IPythonのdisplayツール用のAPIで,音楽ファイルを再生するための IPython.display.Audio やrawデータを画像に変換するための IPython.display.Image などがあります[10].
その中でも, IPython.display.HTML を用いて, style 要素をレンダリングすることでnotebookのCSSをオーバーライドすることができます.

IPython.displayを用いたCSSのオーバーロード

 

notebookから IPython.display を用いたCSSのオーバーライドは以下のようなコードで行うことができます.

上記のコードで今すぐお手元のJupyter notebookにロードすることができます
前述のSnippets Menuなどを使用すれば,このコードを覚える必要もありません.

また,この方法でJupyter Labのカラースキームを変更することもできます.
下画像で読み込んでいるCSSは,こちらです.
また,Jupyter notebookの場合と同様に今すぐお手元のJupyter Labにロードすることができます(CSSのURLを変更する必要があります).

monokai風Jupyter Labカラースキーム

 

また,本稿では詳細は示しませんが,Jupyter Labの場合,「Top Panel > Setting > JupyterLab Theme」に表示されるテーマとして追加することでボタンを押すだけでカラースキームを変更することができます.

Jupyter Labに内包される既存のlight-theme[12]などを参考にしてビルドすることでテーマとして追加することができます.

Jupyter Labのテーマ追加

 

IPython.display を用いる方法は便利ですが,Google ColaboratoryにCSSを適用することはできません.

2.3 Stylus[11]

notebookのカラースキームを変更する3つ目の方法は,Stylusを使用する方法です.
これは,Google ColaboratoryのCSSを変更することも可能です.

Stylusは,webページのスタイル変更を行うことができるブラウザエクステンションです.
URL毎に指定したCSSを適用することができます.

stylus設定画面

 

ColaboratoryのCSS変更

 

2.4 notebookのCSS定義方法

Jupyter notebook,Jupyter Lab,Google ColaboratoryのそれぞれのHTMLのclass属性やid属性は,微妙に異なっています.
しかし,セルの入力部分にはどれもCodeMirrorが使われています.

カラースキーム全体ではなく,シンタックスハイライトのみを変更したい場合は,CodeMirrorの要素を変更する40行ほどのCSSで対応することができます.

Jupyter notebookオリジナルのシンタックスハイライトとone light風のシンタックスハイライト

 

上記の画像をみてください.
左側はJupyter notebookオリジナルのシンタックスハイライトです.右側はone light風のシンタックスハイライトです.

one light風のシンタックスハイライトは,以下のようなCSSで再現することが可能です.

上記のCSSとnotebook上のコードの対応は以下です.

  • cm-comment:コメント
  • cm-keyword:ifelse などの制御キーワード
  • cm-variable:変数
  • cm-operator:+= などのオペレータ
  • cm-def:defの後に来る定義関数名
  • cm-property:オブジェクトのプロパティ・メソッド
  • cm-builtin:ビルトイン変数・関数
  • cm-number:数字(小数点含む)
  • cm-string:クォートで囲まれた文字

colorを変更して,自分のnotebookに適用してみてください.
上記で説明した通り,適用方法は,3つあります.
ここでは最も手軽な 2.2 IPython.display で適用してみましょう.
以下のコードをnotebookで実行するだけです.

Google Colaboratoryに適用する際には, .cm-s-ipython.cm-s-default に変更する必要があるので注意してください.
また,Jupyter notebookで .cm-s-default は,notebook内のmarkdownセルのクラス属性を表すので注意が必要です.

Jupyter notebook,Jupyter Lab,Google ColaboratoryのmonokaiのカラースキームをGithubに上げていますので,背景色などを変更したい場合はこちらを参考にしてください.
jupyterthemesのテーマを元に自分好みに編集してもいいかもしれません.

Jupyter notbook monokail風CSSの例では,1~14行目に背景色,フォントのカラーパレットを定義しています.

このカラーパレットを変更することでJupyter全体の背景色,フォント色の変更が可能なので簡単に独自のカラースキームを作成することができるかと思います.

シンタックスハイライトに関しては,361行目からの .cm-s-ipython span.** の部分を前述の対応を見ながら変更すると良いでしょう.

2.5まとめ

ここではJupyter notebookのカスタムCSSを定義することでnotebookの見た目を自分好みに最適化する方法を3つ紹介しました.
1つ目は,custom.cssを定義する方法です.
2つ目は,notebookから IPython.display を用いる方法です.
3つ目は,Stylusを使う方法です.

1つ目のcustom.cssを定義する方法はnotebookの設定を変更してしまうため,個人に最適化しすぎた場合,他人にとって見づらくなり,また,再設定が手間になります.そのため,個人仕様に限られた場合で使うのが適しているでしょう.notebookをダウンロードして共有する環境の場合もこの方法が適しています.

2つ目のIPython.display を用いる方法は,CSSをロードするためのコードを使い回す必要があります.しかし,1 notebookにおけるコードの再利用 で紹介した方法を使用すれば,コピー&ペーストのための時間を取ることはないでしょう.

3つ目のStylusを使う方法は,上記2つの方法が適用できないGoogle ColaboratoryにもCSSを適用することが可能です.また,他の人に画面を少しの間見せるなどの場面で簡単にオリジナルのCSSに戻せるのでStylusの使用が可能であれば,最も良い方法かもしれません.

ぜひ,自分に合ったカラースキームを作ってみてください.

3 notebookでのコードのデバッグ

Jupyter notebookで動くコードを組み立てていく際,どのように組み立てていくでしょうか?
実行したセルが出力したエラーを愚直に修正していくでしょうか?
notebookが小さくコードが少ない場合はそれでもいいかもしれません.
しかし,notebookが大きくなり,セルが依存する変数が増え,また,メソッドやクラスが大きくなった時,その方法では徐々に辛くなるでしょう.

本章では,Jupyter notebookで動くコードを組み立てていく際のコードデバッグに関する技術を紹介します.

3.1 Embedding IPython

上記のような foo という関数があるとします.
6行目の for 文終了時点で 変数c の中身を確認したい場合あなたならどうしますか?
コード量が増加するほど,1行目から追って c の中身を推定するのは理に適っていません.
変数d の定義の前に return を書いて c を出力させて確認しますか?
それも悪くないかもしれません.ですが,もっといい方法があります.
それは, IPython.embed を使う方法です.

IPython.embedの例

 

IPython.embed を使うことで,任意の箇所からIPythonセッションを開始することができます.
画像の例では,foo 関数の9行目に embed() を差し込むことで,変数d の定義の前にIPythonセッションを開始し,c の中身を確認しています.
IPython.embed で開始いしたIPythonセッションは一般的なIPythonシェルと同じ動作をします.
IPythonセッションから離脱する場合は, exit と入力します.

3.2 ipdb

Pythonでは,対話型ソースコードデバッガとしてpdbが提供されています[14] (IPythonではipdb).
%debug マジックコマンドはpdbの事後解析デバックを有効に活用する手段です.

例外発生後に%debug マジックコマンドを使うことで,ipdbを起動し,例外が発生したコードの周辺を探索することができます.

例えば,上記のような foo という関数があるとします.
この関数では,10行目で例外が発生することは自明です.

debugマジックコマンドの例

 

例外発生後に%debug マジックコマンドを使うことで,ipdbを起動している様子がわかるかと思います.
今回の場合は例外の理由が自明ですが,ipdbには変数の中身を表示する機能や,Pythonコードを実行する機能など最低限の機能が実装されているので例外の発生原因を追求することが可能です.

ipdb(pdb)の操作方法については有志によってcheetsheetが作られているので参照すると良いでしょう.

3.3 その他デバッグに関するTips

3.3.1 tbマジックコマンド

%tb マジックコマンドは最後のトレースバックを表示するマジックコマンドです.

例外が発生したセルの出力を上書きしてしまった場合でも,セルを元に戻す事なく以前のトレースバックを表示することができます.

tbマジックコマンドの例

 

3.3.2 InteractiveShell.ast_node_interactivity

InteractiveShell.ast_node_interactivity により対話的に出力するコードの設定を行うことができます.

本来は,以下のように最後に評価した式のみ対話的に出力されます.

InteractiveShellの対話的出力

 

しかし,InteractiveShell.ast_node_interactivity = "all" と設定することで,全ての式を対話的に出力することができます.

InteractiveShellの対話的出力2

 

~/.ipython/profile_default/ipython_config.py に設定を書き込むことで,全てのnotebookにこの設定を適用することも可能です.

4 notebookを用いたプロファイリング

4.1 cProfileの活用

ここではJupyter notebookを用いたプロファイリングの方法について言及します.
実際,Jupyter notebookでは簡単にプロファイリングができます.

%timeit ラインマジックコマンド,あるいは %%timeit セルマジックコマンドによって timeit モジュールを用いたコード実行時間の計測が行えることは周知の事実ですが,これらのコマンドはコードのどの部分で実行時間がかかっているかまで示してくれません.

timeitコマンドの例

 

Pythonでは,cProfileというプロファイラーが提供されています[13].
Jupyter notebookでは %prun マジックコマンドと %%prun セルマジックコマンドを使って,cProfileを簡単に活用することができます.

prunコマンドの例

 

prunコマンドの結果は,少し見づらいと感じる方もいるかもしれません.
Jupyter notebookでは,line_profilermemory_profilerのマジックコマンドも使うことができます.

4.2 行ベースのプロファイリング

line_profilerは行毎にどのコードの実行に時間がかかったか,memory_profilerはコードの実行にどれだけメモリを使ったかが一目でわかります.

これらを使うには,まず,line_profilerとmemory_profilerをインストールします.
以下のコマンドでnotebookからライブラリをインストールします.

次に %load_ext マジックコマンドによってline_profilerとmemory_profilerのIPython拡張モジュールをインポートします.

これによって, %lprun マジックコマンドと %mprun マジックコマンドが使えるようになります.

lprunとmprunの例

 

line_profilerは行毎にどのコードの実行に時間がかかったか,memory_profilerはコードの実行にどれだけメモリを使ったかが一目でわかります.

4.3 IPython拡張のオートロード

しかし,このままでは,毎回%load_ext マジックコマンドでextensionのロードを行う必要があります.
IPython拡張をnotebookの起動時にインポートするには,c.InteractiveShellApp.extensions を追記する方法があります.

この機能を使うには 1.2.1 startup機能使い方 と同様にプロファイルを作成する必要があります.
notebook上から以下のコードを実行することで,プロファイルの作成と拡張モジュールの自動読み込み設定が完了します.

これによって立ち上げたばかりのnotebookでも,%lprun マジックコマンドと %mprun マジックコマンドが使えるようになります.

おわりに

ここまでご覧いただきありがとうございました.
本稿では,業務の内外で得たJupyterのTipsをいくつか挙げました.
今後も社内外でJupyterの知見をより展開できればと考えています.

最後になりましたが,本稿が皆様の作業の生産性を向上することができるような知見を提供できていれば幸いです.

参照

  1. https://recruit-tech.co.jp/blog/category/data-analytics/
  2. https://pycon.jp/2017/ja/schedule/presentation/38/
  3. https://pycon.jp/2017/ja/
  4. https://conferences.oreilly.com/jupyter/jup-ny/schedule/2018-08-21
  5. http://jupyter.org/
  6. https://github.com/jupyter/jupyter/wiki/Jupyter-kernels
  7. Mary Beth Kery et al. The Story in the Notebook: Exploratory Data Science using a Literate Programming Tool. CHI ’18. ACM, New York Paper 174, p.11.
  8. Adam Rule et al. Exploration and Explanation in Computational Notebooks. In Proceedings of the 2018 CHI Conference on Human Factors in Computing Systems (CHI ’18). ACM, New York, Paper 32, p.12.
  9. https://github.com/ipython-contrib/jupyter_contrib_nbextensions
  10. https://ipython.readthedocs.io/en/stable/api/generated/IPython.display.html
  11. https://add0n.com/stylus.html
  12. https://github.com/jupyterlab/jupyterlab/tree/master/packages/theme-light-extension
  13. https://docs.python.jp/3/library/profile.html
  14. https://docs.python.jp/3/library/pdb.html
  15. https://gist.github.com/jasongrout/753216b2d3320b0abec6143d36f5d640