現代のエンジニアのための強力なメモ帳 Jupyter notebookのすゝめ

会員事業部の有賀(id:chezou)です。 今年一年、社内では勝手に"Jupyterの伝道師"を標榜してJupyter notebookの普及活動を展開してきました。 先日、社内でハンズオンも行ったおかげもあり、かなり社内のマシンにPython環境が構築されてきました :)

Jupyter notebookとは?

ひとことで言うとブラウザで動くすごい便利なREPL*1です。 百聞は一見にしかず、見てみましょう。

f:id:chezou:20151211081910g:plain

このように、Rubyの対話環境であるpryを触っているようにインタラクティブにコードを書くことができます。 以降で説明をしますが、Jupyter notebookは記録・共有・再現がとても得意です。特に図表があるときにその効果を発揮します。

Jupyter notebookの良い所

過去のコードを改変、再実行できる

f:id:chezou:20151211111845g:plain

セルと呼ばれる入力部分にはMarkdownやコードが記述できます。ここのコードはShift+Enterで実行可能なのですが、何度も修正して再実行することができます。 パラメータを少しずつ変えて再実行したりすることがとても容易です。 保存をしたければそれをCtrl+Sで保存すれば良いので*2、たんなるconsoleよりもコードと実行結果を後に残すことが容易です。

私も自分の主催する勉強会(kawasaki.rb)のパーフェクトRuby読書会で1年以上使っていますが、いちいちhistoryを記録に残したりする面倒がないのでとても重宝しています。

画面を切り替えずにコードを書きながらグラフの描画もできる

Jupyter notebookでは書いたコードの描画結果を埋め込むことができます。棒グラフ、折れ線グラフ、箱ひげ図など大抵のグラフが描けます。 画像はbase64 encodeされて保存されるので、notebookの中に保存することができます。

グラフ付きのnotebookを簡単に共有できる

保存したnotebookは簡単に共有することができます。 notebook自体はjson形式で保存されるのですが、Githubのレポジトリやgistに置けばグラフなどの画像とともにそのままレンダーされます。 Github Enterpriseをお使いの場合もnbviewerを使えばURLを使ったnotebookの共有ができます。

いろんな言語が実行環境としてある

Jupyter notebookはもともとPython向けのツールIPython notebookとしてスタートしたのですが、version 3.0でカーネルを分離し名前も変わりました。 これにより、各言語のカーネルを導入することでJupyter上でRuby, Julia, R, Sparkなど様々な言語が動きます。*3

SQLのメモ帳としてのJupyter notebook

サービスの改善や新機能をリリースした時には、ダッシュボードをつくる前に、TreasureDataやRedshift、BigQueryに蓄積されたログに対してSQLでアドホックに分析しますよね。

クックパッドの場合、TDとRedshiftを利用しているのですが、以前は以下の様な手順でアドホック分析をしていました。

  1. console/SQL clientでTD/Redshiftにクエリを実行
  2. 取得結果をcsvで保存
  3. Google spreadsheetに貼り付けてグラフ化する
  4. ダメだったら1に戻る
  5. 良いグラフが得られたら共有する

なんどもなんども2と3を往復するのが結構面倒です。

Jupyter notebookを使うと

  1. Jupyter notebookでクエリを実行しグラフを描き試行錯誤する
  2. 良い結果が得られたらnotebookを共有する

というように1ストップでできるようになります。

これは、pandasというライブラリの恩恵がとても大きいです。 pandasは、表形式のデータ構造DataFrameとグラフ描画をシームレスに扱えるライブラリです。*4 R言語でDataFrameが生まれましたが、pandasでより便利に進化しています。

pandas-tdredshift-sqlalchemyを使うと、TDやRedshiftなどの接続も簡単にできます。実験的にBigQueryもサポートされているようです*5

さきほどのアニメーションgifでもお見せした、Redshiftのデータを扱ったものがこちらです。 データの例としてUCI Machine Learning RepositoryからBankデータを利用しています。 結婚しているかどうかという属性ごとの預金を描画した箱ひげ図や、学歴毎による年齢と預金の散布図などが描画されています。

gist.github.com

Jupyter Tips

環境構築

Pythonに慣れていない方は、Minicondaを使って環境構築をするのが簡単なのでおすすめです。*6私はpyenvとminicondaで環境を作るのを好んでいます。 Treasure Data社のブログが導入方法としてわかりやすいです。

慣れている方はお好きな方法で環境構築していただければと思いますが、社内で聞くとPythonに強い人はpyenvとpyenv-virtualenvwrapperを組み合わせている人が多いようです。

Redshift/TDは以下のパッケージを追加すると便利に使えます。BigQueryはpandas自身が実験的にサポートしています。

  • Redshift
    • redshift_sqlalchemy
    • ipython-sql
  • TD
    • pandas-td

なお、pandas-tdはクエリを実行したらWeb consoleのURLと実行状況が出てきてとても便利です。

f:id:chezou:20151211112918p:plain

また、feature requestを送ったら1時間チョットで対応してくれたなど、TreasureData社が手厚くサポートしてくれています。 このリクエストのおかげで、jobの実行結果を後から取ることができるようになりました。

パスワード周り

DBに接続するためのパスワードなどは、環境変数に指定するなどして、notebookに直接埋め込まないようにしましょう。 これは、notebookを共有した時にうっかりパスワードも共有してしまうのを防ぐためです

弊社では、環境変数で管理するためにenvchainを使っています。

notebook用のディレクトリをgitで管理する

個人的なオススメの使い方としては、~/notebooksというディレクトリを作成し、そこでJupyter notebookを起動しgitで管理することです。

こうすることで、自分用のメモを貯めては定期的にrepositoryをpushし、いい結果が見つかればそれを簡単に共有できます。

終わりに

今日はRubyKaigi 1日目ですが、Jupyter notebookはPythonistaの間だけで使われているのはもったいない!と思って紹介しました。 特にpandasはあまりPythonっぽい記法ではなく、Rubyistな方々も是非一度試してみていただければと思います。

Rubyではnyaplotやdaruなどを使えばnotebookでグラフ描画もできますが、pandasに比べるとまだまだ改善の余地は大きそうです。 こうしたグラフ描画周りや行列計算が充実していき、Rubyでも科学技術計算が盛んになることを期待しています。

*1:対話型の実行環境

*2:autosave機能もあるので突然のカーネルパニックにも安心

*3:なお、Jupyterの"Ju"はJuliaのJuです

*4:@lchin 曰く「RubyのキラーアプリがRailsならPythonのキラーアプリがpandasだ」

*5:残念ながら、BigQueryとpandasは筆者は使ったことがありません

*6:numpy, scipyなどの導入はハマると結構大変だが、minicondaは一通り面倒を見てくれるので初心者には良い

/* */ @import "/css/theme/report/report.css"; /* */ /* */ body{ background-image: url('http://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527163350.png'); background-repeat: repeat-x; background-color:transparent; background-attachment: scroll; background-position: left top;} /* */ body{ border-top: 3px solid orange; color: #3c3c3c; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; line-height: 1.8; font-size: 16px; } a { text-decoration: underline; color: #693e1c; } a:hover { color: #80400e; text-decoration: underline; } .entry-title a{ color: rgb(176, 108, 28); cursor: auto; display: inline; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; font-size: 30px; font-weight: bold; height: auto; line-height: 40.5px; text-decoration: underline solid rgb(176, 108, 28); width: auto; line-height: 1.35; } .date a { color: #9b8b6c; font-size: 14px; text-decoration: none; font-weight: normal; } .urllist-title-link { font-size: 14px; } /* Recent Entries */ .recent-entries a{ color: #693e1c; } .recent-entries a:visited { color: #4d2200; text-decoration: none; } .hatena-module-recent-entries li { padding-bottom: 8px; border-bottom-width: 0px; } /*Widget*/ .hatena-module-body li { list-style-type: circle; } .hatena-module-body a{ text-decoration: none; } .hatena-module-body a:hover{ text-decoration: underline; } /* Widget name */ .hatena-module-title, .hatena-module-title a{ color: #b06c1c; margin-top: 20px; margin-bottom: 7px; } /* work frame*/ #container { width: 970px; text-align: center; margin: 0 auto; background: transparent; padding: 0 30px; } #wrapper { float: left; overflow: hidden; width: 660px; } #box2 { width: 240px; float: right; font-size: 14px; word-wrap: break-word; } /*#blog-title-inner{*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-position: left 0px;*/ /*}*/ /*.header-image-only #blog-title-inner {*/ /*background-repeat: no-repeat;*/ /*position: relative;*/ /*height: 200px;*/ /*display: none;*/ /*}*/ /*#blog-title {*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-image: url('http://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527172848.png');*/ /*background-repeat: no-repeat;*/ /*background-position: left 0px;*/ /*}*/