この投稿は 「jupyter notebook Advent Calendar 2016 - Qiita」 の 6日目の記事です。
今年の流行語大賞が 「JPAP(Jupyter / Python / Anaconda / Pyenv) に決まりましたね!
あれ? 違うの!?
といった冗談はさておき、ちょっとした統計解析をしようとしたときに、Jupyter Notebook(ジュピター ノートブック)+ Pandas(パンダス)を試してみたら、すごくいい感じだったのでご紹介。
Jupyter Notebook はブラウザ上でデータ分析関連の Python コードを実行したり実行結果を保存したりすることができる非常に便利なツールなのですが、Jupyter Notebook の他にも Python, NumPy, Pandas, Matplotlib 等々の環境を準備しておく必要があります。それをゼロから用意するのは大変だなぁと思うかもしれませんが、「Anaconda」というデータサイエンティスト向けのプラットフォームをインストールするだけで、Python 本体を含めたデータ分析関係の Python パッケージ群をいい感じに環境設定することができます。 *1
また Anaconda は、「Pyenv」という Python のバージョン管理ツールを使うことで、Mac や Linux などの環境に適当な Anaconda を簡単にインストールをすることができます。
ということで今回は、「JPAP(Jupyter / Python / Anaconda / Pyenv)」(Jupyter はじめるなら、データ分析関連の Python パッケージが全部入りの Anaconda を Pyenv でインストール!)と題して、Jupyter Notebook のセットアップ、および使ってみた感想を書いてみます。
まずは、Jupyter Notebook や Pandas の概要から。
Jupyter Notebook
Jupyter Notebook は、ブラウザ上でデータ分析関連の Python コードを実行したり実行結果を保存したりすることができる非常に便利なツールです。サーバを裏で起動しておくことで、ブラウザ上のいろいろな操作を受け付けることができます。
(参考)
A gallery of interesting IPython Notebooks · ipython/ipython Wiki · GitHub
ちなみに、Jupyter Notebook は少し前まで「IPython Notebook」と呼ばれていました。公式としては、2015年7月末から名前が変更になったということでしょうかね。
Jupyter Notebook was born (officially on July 30)
以下、Jupyter Notebook を使ってみた感想です。
Jupyter Notebook の良いところ
- Anaconda さえあれば他にセットアップ不要
- 画面でポチポチしてデバッグできる *2
- 実行結果を含めて ipynb ファイルに保存できる *3
- ipynb ファイルを GitHub にアップすれば誰でも実行結果を見れる
(例:bgstat/analytics_by_experience.ipynb at master · akiyoko/bgstat · GitHub)
少し足りないところ
- 変数の中身が全て出力されないところ(長いと「...」と省略されてしまう)
- GitHub の画面でポチポチできない
Pandas
「Pandas は、非常に便利に使える Python のデータ分析ライブラリです。DataFrame や read_excel、read_csv など、ありがたい機能が盛り沢山です。
pandas is an open source, BSD-licensed library providing high-performance, easy-to-use data structures and data analysis tools for the Python programming language.
JPAP(Jupyter / Python / Anaconda / Pyenv)の手順
Anaconda を Pyenv でインストールします。
以下、Mac 上でのインストール手順になります。
<過去記事>
akiyoko.hatenablog.jp
1.Pyenv のインストール
Homebrew で pyenv をインストールします。
$ brew install pyenv $ pyenv --version pyenv 20160303 $ cat << EOF >> ~/.bash_profile export PYENV_ROOT=\${HOME}/.pyenv export PATH=\${PYENV_ROOT}/bin:\$PATH eval "\$(pyenv init -)" EOF $ source ~/.bash_profile
2.Anaconda のインストール
Anaconda 2 は Python 2.7系、Anaconda 3 は Python 3.5系のパッケージを同梱しています。 *4
私は(業務で使っているのが)Python 2系なので、最新の Anaconda 2 をインストールすることにしました。
ちなみに anaconda2-2.4.0 以降、 Anaconda 2 系のプレフィックスが「anaconda2-*」に統一されたようです。 *5
$ pyenv install -l Available versions: 2.1.3 ・ ・ anaconda-2.4.0 anaconda2-2.4.0 anaconda2-2.4.1 anaconda2-2.5.0 anaconda3-2.0.0 ・ ・
Anaconda 2系で(現時点で)最新の「anaconda2-2.5.0」をインストールしました。
$ pyenv install anaconda2-2.5.0 $ pyenv global anaconda2-2.5.0 $ pyenv rehash ### バージョン確認 $ pyenv versions system anaconda-2.4.0 * anaconda2-2.5.0 (set by /Users/akiyoko/.pyenv/version) $ python --version Python 2.7.11 :: Anaconda 2.5.0 (x86_64) $ pip list | grep -E "jupyter|notebook" jupyter (1.0.0) jupyter-client (4.1.1) jupyter-console (4.1.0) jupyter-core (4.0.6) notebook (4.1.0)
ここで一瞬ハマってしまいました。。
conda update を実行して最新化しようとしたら、Python が 2.7.12 にアップグレードされてしまい、Jupyter Notebook 利用時に新規ファイルを作成しようとすると、「Python[conda root]」と「Python[default]」の 2バージョンが表示されてしまいました。
python 2.7.12 installed from anaconda and the default one came with Mac is 2.7.10.
が原因かもしれません。
結局、conda update でアップデートするのはやめました。
3.Jupyter Notebook の起動方法
コマンドラインから以下を実行すれば OK です。
$ jupyter notebook
サーバ起動後にブラウザで「http://localhost:8888/」にアクセスすると、サーバを起動したディレクトリが階層表示されます。
あとはポチポチやるだけ。
実戦
ちょっとしたデータ解析をしてみました。
こんな感じで、D列から右方向にデータ列が並んでいる Excel シートがあるとします。
まずは、Pandas の read_excel() を使って Excel を読み込みます。
少し前処理をした後、DataFrame を加工して、偏差値などの代表値を加えたり、欠損値を除外したり、データをソートしたり、各代表値を計算したりします。
最後に、経験年数ごとにグループ化してグラフを描きました。
import matplotlib.pyplot as plt import numpy as np import pandas as pd %matplotlib inline # header 無しで Excel を読み込む excel_df = pd.read_excel('5th_backgammon_proficiency_test_score.xls', sheetname='Result', header=None)
「%matplotlib inline」は実行結果の画像をインラインで埋め込むためのおまじない。
# D列以降のデータのみを使用 df = excel_df.copy() df = df.ix[:, 3:]
pandas.DataFrame.ix を使うと、DataFrame のスライスが簡単にできます。
# index と column を反転 df = df.T
今回試した Excel データが右方向にデータ列が並んでいるため、少しトリッキーなことをしました。
# column名を書き換え columns = { 0: 'Date', 3: 'Nation', 4: 'Sex', 7: 'Experience', 61: 'Total Score', 64: 'Total Error', 118: 'Early Game Score', 119: 'Middle Game Score', 120: 'End Game Score', 121: 'Other Score', 132: 'Early Game Error', 133: 'Middle Game Error', 134: 'End Game Error', 135: 'Other Error', } df.rename(columns=columns, inplace=True) # column の絞り込み df = df[columns.values()]
# Date列が NaN のデータは除外 df = df.dropna(subset=['Date'])
pandas.DataFrame.dropna() で欠損データを除外することができます。
def get_deviation(s): """ s: Series """ return (s - s.mean()) / s.std(ddof=False) * 10 + 50 # 偏差値列を追加 df['Deviation of Total Score'] = get_deviation(df['Total Score']) df['Deviation of Early Game Score'] = get_deviation(df['Early Game Score']) df['Deviation of Middle Game Score'] = get_deviation(df['Middle Game Score']) df['Deviation of End Game Score'] = get_deviation(df['End Game Score']) df['Deviation of Other Score'] = get_deviation(df['Other Score']) df['Deviation of Total Error'] = 100 - get_deviation(df['Total Error']) df['Deviation of Early Game Error'] = 100 - get_deviation(df['Early Game Error']) df['Deviation of Middle Game Error'] = 100 - get_deviation(df['Middle Game Error']) df['Deviation of End Game Error'] = 100 - get_deviation(df['End Game Error']) df['Deviation of Other Error'] = 100 - get_deviation(df['Other Error'])
# Total Score列の降順、Total Error列の昇順でソート df = df.sort_values(by=['Total Score', 'Total Error'], ascending=[False, True]) df
pandas.DataFrame.sort_values() でソートができます。
# 各代表値を求める sliced = df[['Total Score', 'Early Game Score', 'Middle Game Score', 'End Game Score', 'Other Score', 'Total Error', 'Early Game Error', 'Middle Game Error', 'End Game Error', 'Other Error']] desc = pd.DataFrame( [sliced.max(), sliced.min(), sliced.mean(), sliced.median(), sliced.var(ddof=False), sliced.std(ddof=False)], index=['max', 'min', 'mean', 'median', 'var', 'std'] ) desc
# その他の統計量 df.describe()
# 前処理ここまで # 経験年数ごとにグループ化 grouped = df.groupby('Experience') # 出力用のデータフレームを作成 experience_df = pd.DataFrame() experience_df['Size'] = grouped.size() experience_df['Total Score'] = grouped['Total Score'].apply(np.mean) experience_df['Early Game Score'] = grouped['Early Game Score'].apply(np.mean) experience_df['Middle Game Score'] = grouped['Middle Game Score'].apply(np.mean) experience_df['End Game Score'] = grouped['End Game Score'].apply(np.mean) experience_df['Other Score'] = grouped['Other Score'].apply(np.mean) experience_df['Total Error'] = grouped['Total Error'].apply(np.mean) experience_df['Early Game Error'] = grouped['Early Game Error'].apply(np.mean) experience_df['Middle Game Error'] = grouped['Middle Game Error'].apply(np.mean) experience_df['End Game Error'] = grouped['End Game Error'].apply(np.mean) experience_df['Other Error'] = grouped['Other Error'].apply(np.mean)
# indexの並び替え experience_df = experience_df.reindex(['under 1 year', '1-2 years', '2-3 years', '3-4 years', '4-5 years', '5-10 years', 'over 10 years']) experience_df
pandas.DataFrame.reindex() で index の並び替えができます。
# スコアのグラフ描画 experience_df.plot.bar( y=['Early Game Score', 'Middle Game Score', 'End Game Score', 'Other Score'], figsize=(10, 8), stacked=True, cmap='Blues') plt.title(u'Score by Experience', size=16) plt.plot()
pandas.DataFrame.plot.bar で棒グラフを描画することができます。
# エラーのグラフ描画 experience_df.plot.bar( y=['Early Game Error', 'Middle Game Error', 'End Game Error', 'Other Error'], figsize=(10, 8), stacked=True, cmap='Blues') plt.title(u'Error by Experience', size=16) plt.legend(loc='upper right') plt.plot()
まとめ
冒頭でも書きましたが、ちょっとした統計解析をしようとしたときに Jupyter Notebook + Pandas を試してみたら、すごくいい感じでした。
Jupyter Notebook を使うための環境は、Anaconda をインストールすればゼロからでも一発で準備することができるので、非常に楽チンです。
Anaconda には、Python 本体や Jupyter Notebook のほか、Numpy や Pandas、Matplotlib までデータ分析に必要なライブラリが一通り揃っているので、あとはブラウザを使ってトライ&エラーでデータ分析を進めていくことができます。気軽にデータ分析を試すことができ、ipynb ファイルで実行結果を共有したりすることもできるので、非常に面白いツールだと感じました。
明日は、7of9 さんの 7日目の記事「Jupyter Notebook > NewボタンでPython2が選択できない時の対処方法 / Jupyterの気に入っているところ - Qiita」です。
よろしくお願いします。
参考本
「IPython」とタイトルに付いていますが、比較的新しい本です。
「IPython Notebook」は 2015年7月以降に「Jupyter Notebook」に改名されましたが、「IPython」自体は消滅したわけではなく、インタラクティブ Python シェルや Jupyter の Python 用のカーネルとして存在しています。
- A powerful interactive Python shell
- A Jupyter kernel to work with Python code in Jupyter notebooks and other interactive frontends.
*1:Anaconda に含まれるパッケージの一覧は、「Anaconda package lists | Anaconda: Documentation」から確認することができます。
*2:jupyter notebook コマンドでサーバを立ち上げる必要があります
*3:出力したグラフ(画像)もインライン表示で含めることができます