まずは蝋の翼から。

学んだことを書きながら確認・整理するためのメモブログ。こういうことなのかな?といったことをふわっと書いたりしていますが、理解が浅いゆえに的はずれなことも多々あると思うのでツッコミ歓迎

pandasのstyleでテーブル出力をわかりやすくする

JupyterにおけるPandasのテーブルデータの出力に色をつけてわかりやすくしたい。

そのためには、pandasのstyle周りをいじれば良いみたい。
基本的にドキュメントのUser Guideベースで書いていく。

pandas.pydata.org

pandas.pydata.org

styleのいじり方は2つあり、1つは組み込みメソッドをそのまま使うやり方。もう1つは自分でCSSを指定する関数を定めてapplyapplymapを適用する(前者は値に、後者は行/列に適用)。

データはテキトーに以下を使う。

import pandas as pd
import numpy as np

np.random.seed(24)
df = pd.DataFrame({'A': np.linspace(1, 10, 10)})
df = pd.concat([df, pd.DataFrame(np.random.randn(10, 4), columns=list('BCDE'))],
               axis=1)
df.iloc[3, 3] = np.nan
df.iloc[0, 2] = np.nan
df.head()

f:id:chito_ng:20200503170742p:plain:w400

Builtin styles

一般的によく使うものに対して組み込みでメソッドがあるのでそれをそのまま使うやり方。

Nullの背景色指定

style.highlight_null()でNullの背景色を指定できる。

df.style.highlight_null(null_color='red')

f:id:chito_ng:20200503172203p:plain:w400

連続値のグラデーション背景

連続値に対してグラデーションで背景指定。

background_gradientで指定する。

pandas.pydata.org

引数cmapに対してカラーマップを指定することでグラデーションを指定する。

カラーマップは Matplotlib colormapseabornのカラーマップ(パレットが使える

df.style.background_gradient(cmap='viridis', low=.5, high=0) # Matplotlib colormapのviridisにして、0.0 - 5.0のレンジでグラデーション

f:id:chito_ng:20200503214054p:plain:w400

import seaborn as sns

cm = sns.light_palette("green", as_cmap=True) # seabornのlight_paletteで緑グラデーションオブジェクトを作成

df.style.background_gradient(background_gradient=cm) # 緑グラデーションオブジェクトの適用

f:id:chito_ng:20200503172731p:plain:w400

ちなみに、どうやらbackground_gradientcmapはMatplotlib colormapだとnan含めて色づけられるがseabornカラーマップだと最小値と同じ色になるっぽい?別の色を指定したい場合はhighlight_nullでnan背景を上書きする。


matplot_color = df.style.background_gradient(cmap='viridis') # Matplotlib colormap

cm = sns.light_palette("green", as_cmap=True)
sns_color = df.style.background_gradient(cmap=cm) # Seaborn colorpalette
sns_color_nan = df.style.background_gradient(cmap=cm).highlight_null('black') # Seaborn colorpalette + nanを黒にする


display(matplot_color,sns_color,sns_color_nan)

f:id:chito_ng:20200504094513p:plain:w400

最大最小値のハイライト

highlight_maxで最大値を、highlight_minで最小値をハイライトする。

pandas.pydata.org

pandas.io.formats.style.Styler.highlight_min — pandas 1.0.3 documentation

df.style.highlight_max(axis=0,color='red') # 列毎の最大値

f:id:chito_ng:20200503214855p:plain:w400

df.style.highlight_max(subset='B', color='grey') # A列の最大値

f:id:chito_ng:20200503214927p:plain:w400

df.style.highlight_min(axis=None,color='red') # 全体の最小値

f:id:chito_ng:20200503214825p:plain:w400

値のフォーマット

formatで値のフォーマットを変えられる。

pandas.pydata.org

df.style.format("{:.2%}") # 2桁でパーセント表示

f:id:chito_ng:20200503221731p:plain:w400

df.style.format({"B": lambda x: "±{:.2f}".format(abs(x))}) # B列に「±」⊥をつけて2桁表示

f:id:chito_ng:20200503221759p:plain:w400

背景に棒グラフを表示

値をもとに、背景に棒グラフを表示する。

pandas.pydata.org

引数alignはleft, zero, midから選択する。それぞれ、

  • left : 最小値が左端になる
  • zero : 0を中央として負の数を中央より左、正の数を中央より右に表示する
  • mid : 正負が混じっているときは(最大値-最小値)/2を中央にする。全てが正の数(負の数)のときは左端(右端)を0とする。

となる。

f:id:chito_ng:20200504084033p:plain:w400

df.style.bar(subset=['A', 'B'], align='zero', color=['#d65f5f', '#5fba7d'])

f:id:chito_ng:20200504084119p:plain:w400

文字精度

set_precisionでx桁表示。

df.style.set_precision(2)

f:id:chito_ng:20200504084821p:plain:w400

CSSで装飾

背景色・文字色・枠線などの色はset_propertiesを使う。
辞書でCSS形式で渡しても良いし、直接引数にしてもよいがドキュメントにあまり例が載ってないので何が使えて使えないのか正直よくわからん。
なお、subsetで列を指定することも可能。

pandas.pydata.org

# 辞書での指定
df.style.set_properties(**{'background-color': 'black', # 背景
                           'color': 'lawngreen', # 文字色
                           'border-color': 'white', # 枠の色っぽいが、変わってない?
                           'align':'left'}) # 文字の揃える位置っぽいが、変わってない?

f:id:chito_ng:20200503220321p:plain:w400

Building styles

自分でCSSを指定する関数を定めてapplymapapplyを適用する(前者は行/列単位、後者は値単位。

CSSを使ったことないのでざっくりと説明。

以下では、渡された値を判定して、負の数で赤、正の数で黒となるCSS指定を返す関数を用いる。
これをapplymapで値毎に判定することで、各値の色を変える。

def color_negative_red(val):
    """
    Takes a scalar and returns a string with
    the css property `'color: red'` for negative
    strings, black otherwise.
    """
    color = 'red' if val < 0 else 'black'
    return 'color: %s' % color # 返り値はCSS文字列

df.style.applymap(color_negative_red)

f:id:chito_ng:20200503220827p:plain:w400

以下は、渡されたSeriesの中での最大値を黄色で表示する関数を用いてapplyを適用している。

def highlight_max(s):
    '''
    highlight the maximum in a Series yellow.
    '''
    is_max = s == s.max()
    return ['background-color: yellow' if v else '' for v in is_max]

df.style.apply(highlight_max) # axisはデフォルトは0なので列に対して適用。1だと行、Noneだと全体。

f:id:chito_ng:20200503221031p:plain:w400

set_table_stylesに直接入れても良い。

styles = [
    dict(selector="th", props=[("font-size", "150%"),
                               ("text-align", "center")])
]

df.style.set_table_styles(styles)

f:id:chito_ng:20200504090340p:plain:w400

複合

なお、これらを組み合わせることができる。

np.random.seed(25)
cmap = cmap=sns.diverging_palette(5, 250, as_cmap=True)
bigdf = pd.DataFrame(np.random.randn(20, 25)).cumsum()

def magnify():
    return [dict(selector="th",
                 props=[("font-size", "4pt")]),
            dict(selector="td",
                 props=[('padding', "0em 0em")]),
            dict(selector="th:hover",
                 props=[("font-size", "12pt")]),
            dict(selector="tr:hover td:hover",
                 props=[('max-width', '200px'),
                        ('font-size', '12pt')])
]

bigdf.style\
    .background_gradient(cmap, axis=1)\
    .set_properties(**{'max-width': '80px', 'font-size': '1pt'})\
    .set_caption("Hover to magnify")\
    .set_precision(2)\
    .set_table_styles(magnify())\
    .highlight_null('black')

f:id:chito_ng:20200504091804p:plain:w400

その他参考

以下のスライドがどちゃくそわかりやすかったしよくまとまっている。

speakerdeck.com