StatsFragments

Python, R, Rust, 統計, 機械学習とか

Python Jupyter + pandas で DataFrame 表示をカスタマイズする

先日 pandas v0.17.1 がリリースされた。v0.17.0 に対するバグフィックスがメインだが、以下の追加機能もあるため その内容をまとめたい。

HTML 表示のカスタマイズ

Jupyer 上では pandasDataFrame は自動的に HTML として描画される。この HTML に対して、さまざまな CSS を柔軟に設定できるようになった。

このエントリでは、添付した公式ドキュメントとは少し違う例を記載する。

重要 公式ドキュメントにも記載がされているが v0.17.1 時点で開発中 / Experimental な追加のため、今後 破壊的な変更が発生する可能性がある。ご要望やお気づきの点があれば GitHub issue か @ ください。

以降、Jupyter にて実行する。まず DataFrame を作成して表示する。

import pandas as pd
import numpy as np

np.__version__
# '1.10.1'

pd.__version__
# u'0.17.1'

np.random.seed(1)

df = pd.DataFrame({'name': list('abcdefg'),
                   'values1': np.random.randn(7), 
                   'values2': np.random.randn(7)})
df

f:id:sinhrks:20151122200445p:plain

v0.17.0 にて DataFrameDataFrame.style アクセサが追加され、これを経由して種々のカスタマイズができる。例えば、各セルの値に応じてカラーマップを適用するには Styler.background_gradient()

type(df.style)
# pandas.core.style.Styler

df.style.background_gradient(cmap='winter')

f:id:sinhrks:20151122200539p:plain

カラーマップの一部範囲の色のみ利用する場合は low, high キーワードで範囲を指定する。

df.style.background_gradient(cmap='winter', low=2.)

f:id:sinhrks:20151122200546p:plain

特定の列にのみ Styler を適用する場合は subset キーワード。

df.style.background_gradient(cmap='winter', low=2., subset=['values1'])

f:id:sinhrks:20151122200646p:plain

さらに特定のセルにのみ適用する場合は 対象セルを指定する pd.IndexSlice インスタンスsubset として指定する。

pd.IndexSlice[2:5, ['values1']]
# (slice(2, 5, None), ['values1'])

# .loc に渡した場合は対象セルのみをスライス
df.loc[pd.IndexSlice[2:5, ['values1']]]

f:id:sinhrks:20151122201309p:plain

df.style.background_gradient(cmap='winter', low=2., subset=pd.IndexSlice[2:5, ['values1']])

f:id:sinhrks:20151122200655p:plain

Stylerbackground_gradient 以外にも 以下のようなメソッドをもつ。

df.iloc[1, 1] = np.nan
df.style.highlight_null()

f:id:sinhrks:20151122200712p:plain

さらに、Styler.set_properties を利用すると任意の CSS を全セルに対して適用できる。数値以外のセルを色分けするにはこれを使えばよい。

df.style.set_properties(**{'background-color': '#00ff7f'})

f:id:sinhrks:20151122200741p:plain

また、Styler はチェインできる。

(df.style.
 set_properties(**{'background-color': '#00ff7f'}).
 background_gradient(cmap='winter', low=2.).
 highlight_null())

f:id:sinhrks:20151122200724p:plain

より柔軟な条件分けのため、 Styler.apply 系のメソッドも持つ。使い方は通常の DataFrame.apply.applymap と同じだが、値そのものではなく CSS を返す関数を適用する。

  • Styler.applymap: 各セルに対して CSS を返す関数を適用 (関数への入力はスカラー)。
  • Styler.apply: 各列もしくは各行に対して CSS を返す関数を適用 (関数への入力は 各列/各行の値からなる Series )。

参考 Python pandas データのイテレーションと関数適用、pipe - StatsFragments

セルの値が 0 より小さい場合は 赤 / 太字で表示する場合は Styler.applymap

def highlight_negative(val):
    if val < 0:
        return 'color: {0}; font-weight: bold'.format('red')
    else:
        return 'color: {0}'.format('black')

df.style.applymap(highlight_negative)

f:id:sinhrks:20151122200800p:plain

各行について、values1 列の値が values2 列の値より大きいときに values1 列のみ 赤背景で表示したい。行ごとに関数を適用するため、axis=1 を指定する。highlight_values1 関数が返す リストの各要素が、各列に適用される CSS に対応している。

def highlight_values1(s):
    if s['values1'] > s['values2']:
        # 
        return ['', 'background-color: red', '']
    else:
        # スタイル変更しない場合は空の文字列のリストを返す
        return [''] * len(s)

df.style.apply(highlight_values1, axis=1)

f:id:sinhrks:20151122200808p:plain

最後に、Jupyterwidget と組み合わせることで動的なスタイル変更ができる。以下ではスライドバーの位置によって フォントの大きさを変更している。

from IPython.html import widgets
@widgets.interact
def f(s=(5, 30)):
    return (df.style.background_gradient('winter', low=2.).set_properties(**{'font-size': '{0}px'.format(s)}))

f:id:sinhrks:20151122200816p:plain

f:id:sinhrks:20151122200825p:plain

Jupyter 以外に 同様の出力を HTML として埋め込みたい場合は、Styler.render() を利用する。

style = df.style.background_gradient('winter', low=2.)
style.render()
# 略 (HTML が文字列として出力される)

ピボットテーブル + グラフ表示

また Jupyter 上での DataFrame の扱いに関連して、データそのものを GUIインタラクティブに操作 / グラフ表示ができるpivottablejs というパッケージがある。

まとめ

pandas v0.17.1 で追加された DataFrame の HTML 表示のカスタマイズ方法について記載した。

Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理

Pythonによるデータ分析入門 ―NumPy、pandasを使ったデータ処理