IPython Notebookをアドホック分析環境として使う

こんにちは、Gunosyのエンジニアの粟飯原です。Gunosyでは、主に広告配信サーバー全般の開発運用インフラを行いつつ、データ集計や分析等を行なっています。

今回は、自分が開発業務や分析業務で日常的に利用しているIPython Notebookを便利に使う方法を紹介させて頂きます。

基本的に、pipでライブラリがインストールできる環境とnumpy、scipyの環境が揃っていることが前提で進めます。windows環境であれば、ライブラリのインストールは以下のURLのパッケージ群を利用すると快適です。とはいえこのページで紹介しているライブラリはwindowsでは動かないものもあります。

今回はIPython Notebookを既に活用している人向けのエントリーになっていますが、逐次更新してPandasとStatsmodelsとScikitsを用いたデータ処理や、統計解析に関する様々なユースケースをこのIPython Notebook上に追記してまとめていきたいと考えています。

IPython Notebookとは

IPython Notebookは、pythonのインタラクティブシェルであるipythonをブラウザ上から利用する為のインターフェイスです。ipythonを起動するときに、オプションにnotebookとつけることで、インタプリタがブラウザ上に起動します。(依存ライブラリなどはこちらを参照 > http://ipython.org/ipython-doc/dev/install/install.html)

ipython notebook

ipythonの機能も含みますが、以下の様な機能と特徴を持っています。

  • ブラウザ上でPythonコードの実行/編集ができる
  • pythonコードの強力な補完機能とシンタックスハイライト
  • グラフもインタラクティブにブラウザ上に表示可能(matplotlibやBokehを利用)
  • 並列分散処理機能(!)
  • markdown形式とlatexの数式記述が可能で、ドキュメントとコードを同時に記述できる
    • (この記事もIPython Notebookでpythonコードを実行しながら記述しています)
  • 作成したnotebookは、reStructuredText、tex、html、pdf、スライド形式などに変換可能
  • バックエンドをpython以外に切り替え可能
    • Julia、Ruby、Haskellを利用可能。中でそのままRを呼んだり、Octaveを呼んだりもできる

分散処理周りは自前で作っているceleryやpyro4の環境があるので基本使っていないのですが、アルゴリズムの確認や、アドホックな集計分析依頼に対応する際には、ブラウザ上でグラフや出力結果を確認しながらコードも快適に記述できるということは集計・解析の作業速度を大幅に早めることになります。

データの分析や、アルゴリズム実装のテストを行うにあたって、IPython NotebookとPythonの分析系のエコシステムは非常に協力なツールです。特に、ビジネスサイドからのアドホックな要求に対して、データの取得、分析処理、可視化をインタラクティブに実行でき、そのすべてのフェーズにおいてPythonの様々なライブラリを利用することができるのがRやMatlabとの大きな差分になります。

GunosyでのIPython Notebook上での非定常的な集計・解析ワークフロー

Gunosyでは、解析用のログ情報をAWS上のRedshiftに蓄積しています。定常的なKPIの取得や可視化等はバッチで集計した上で社内向けのWebアプリケーション上で閲覧することができるようにしています。仮説検証やアルゴリズムの構築検証を行う際に、IPython Notebookを活用しています。VPN経由か、SSH Portforwardingを用いて手元のIPython NotebookからRedshiftを叩いてデータの分析などを行っています。Redshiftから取得したデータをPandasのDataFrameにして処理を加えたあと、インタラクティブに可視化を行いつつ、データの分析やアルゴリズムの開発を日々行っています。

使い倒すTips

  • MatplotlibとBokehを使おう
  • IPython Notebookでネイティブコードコンパイルをして高速化

MatplotlibとBokehを使おう

Pythonでデータの可視化を行うにあたって、標準的にmatplotlibというmatlabやRのplotライブラリのようなインターフェイスで利用可能な協力なplottingライブラリがあり、こちらもIPython Notebook上で気軽に利用することが出来ます。IPython Notebookで利用する場合は、matplotlibをインストールの後に、IPython Notebookを起動する際に、以下のようなオプションをつけることで、そのままブラウザ上で画像を表示することが出来ます。

matplotlibのインストールは、windowsの場合はインストーラで、macやlinuxの場合はportやyum等のパッケージ管理システムでインストールするのが楽ですが、pipでも入ります。

% ipython notebook --pylab inline

IPython Notebookを起動後にplotを呼び出すと、グラフが画像の形でブラウザ上に表示されます。matplotlibの使い方を知っていれば、通常のものと基本的には利用方法は変わらないため、特に問題なくグラフが描画できると思います。subplotで複数のグラフを表示することも可能です。

クロススペクトルを表示するサンプルをIPython Notebook上で実行するとそのまま、IPython Notebookのセルの下にグラフが描画されます。

In [23]:
import numpy as np
dt = 0.01
t = np.arange(0, 30, dt)
nse1 = np.random.randn(len(t))                 # white noise 1
nse2 = np.random.randn(len(t))                 # white noise 2
r = np.exp(-t/0.05)

cnse1 = np.convolve(nse1, r, mode='same')*dt   # colored noise 1
cnse2 = np.convolve(nse2, r, mode='same')*dt   # colored noise 2

# two signals with a coherent part and a random part
s1 = 0.01*np.sin(2*np.pi*10*t) + cnse1
s2 = 0.01*np.sin(2*np.pi*10*t) + cnse2
plt.subplot(211)
plt.xlim(0,5)
plt.plot(t, s1, 'b-', t, s2, 'g-')
plt.xlabel('time')
plt.ylabel('s1 and s2')
plt.grid(True)

plt.subplot(212)
cxy, f = plt.csd(s1, s2, 256, 1./dt)
plt.ylabel('CSD (db)')
plt.show()

IPython Notebookの中でmatplotlibのplotを呼ぶと、そのままpngの画像を生成されてHTMLの中に埋め込まれるのですが、元々の機能としてあった、拡大縮小や移動・回転などがインタラクティブにできなくなってしまいます。画像の生成時にサイズや位置などはいじれますが、インタラクティブにグラフを見ることが出来ないのは不便です。散布図を描画した時など、データ点が密集していると細かいところが見えなかったりするので、拡大縮小はデータ分析時にはとても欲しい機能です。

そこで、IPython Notebook上でインタラクティブにグラフを操作することができるJavascriptベースのプロッティングライブラリがBokehです。

pipでインストール出来ますが、Python自体をAnaconda Scientific Python Distributionに変えて、それのパッケージ管理システムであるcondaを利用すると他のライブラリの導入なども楽にできるようになります。

 $ conda install bokeh
  or
 $ pip install bokeh
 

output_notebookという関数をインポートして実行することで、IPython Notebook上でbokehのグラフ描画が可能になります。

In [2]:
from bokeh.plotting import output_notebook
output_notebook()
Bokeh Plot

Configuring embedded BokehJS mode.

グラフにlineプロットやscatterプロットをする前に、figure関数で描画面を作成します。この際、toolsに拡大縮小や保存等のオプションを付与することで、インタラクティブに操作が可能なグラフを描画できるようになります。描画面を作成後、hold関数を呼ぶことで、ひとつのfigureに複数のプロットを描画することが出来ます。

In [7]:
from bokeh.plotting import line, show, figure, xaxis, hold, yaxis
from bokeh.objects import Range1d
import numpy as np
dt = 0.01
t = np.arange(0, 30, dt)
nse1 = np.random.randn(len(t))                 # white noise 1
nse2 = np.random.randn(len(t))                 # white noise 2
r = np.exp(-t/0.05)

cnse1 = np.convolve(nse1, r, mode='same')*dt   # colored noise 1
cnse2 = np.convolve(nse2, r, mode='same')*dt   # colored noise 2

# two signals with a coherent part and a random part
s1 = 0.01*np.sin(2*np.pi*10*t) + cnse1
s2 = 0.01*np.sin(2*np.pi*10*t) + cnse2
hold()
figure(tools="pan,wheel_zoom,box_zoom,reset,previewsave", title="Signals", plot_height=400)
line(t[:500], s1[:500], color="blue", legend='s1', x_range = Range1d(start=0, end=5))
line(t[:500], s2[:500], color='green', legend='s2', x_range = Range1d(start=0, end=5))
yaxis().axis_label='s1 and s2'
yaxis().axis_label_text_font_size = "12pt"
hold(False)
show()
hold()
figure(tools="pan,wheel_zoom,box_zoom,reset,previewsave", title="CSD", plot_height=200)
csd = matplotlib.mlab.csd(s1, s2, 256, 1./dt)
line(csd[1], np.log10(np.abs(csd[0]))*10, x_range = Range1d(start=0, end=50))
yaxis().axis_label='CSD(db)'
xaxis().axis_label='Frequency'
xaxis().axis_label_text_font_size = "12pt"
yaxis().axis_label_text_font_size = "12pt"
show()
Bokeh Plot
Plots