LoginSignup
12
14

More than 5 years have passed since last update.

Jupyter NotebookでpandasのMultiIndexに色を付ける

Posted at

この記事は ACCESS Advent Calendar 2018 の5日目の記事です。

はじめに

Jupyter NotebookでpandasのDataFrameを表示する際に、CSSでスタイルを設定して色付けすることができます。

本記事では、公式ドキュメント にない例として、MultiIndex構造のDataFrameに特定の条件で色を付けて表示する方法を紹介します。

データの準備

これから色付けしていくベースとなるMultiIndex構造のDataFrameは、pandasのテスト用データセットtips.csvをクロス集計した表を使います。

import pandas as pd

tips = pd.read_csv('https://raw.github.com/pandas-dev/pandas/master/pandas/tests/data/tips.csv')
cross = pd.crosstab([tips.sex, tips.smoker], [tips.day, tips.time])
cross

cross_base.png

以降では、このクロス集計表を元に特定の条件で色付けする例を紹介します。

特定の行全体

def highlight(df):
  # 返り値は、スタイルで埋めたDataFrameです。引数のDataFrameと構造は同じなので`df`をコピーします。
  styles = df.copy()

  # DataFrame全体をスタイル無しで初期化します。
  styles.loc[:,:] = ''

  # `loc[(行の1層目, 行の2層目), (列の1層目, 列の2層目)]`の形式で、スタイルを設定する位置を選択します。
  styles.loc[('Male', 'No'), :] = 'background-color: lightgreen'

  return styles

# `apply`の第一引数の関数`highlight`でスタイルを設定します。
# `axis=None`にすることで、適用元のDataFrame全体が引数として渡されます。
cross.style.apply(highlight, axis=None)

cross_highlight_row.png

特定の列全体

def highlight(df):
  styles = df.copy()
  styles.loc[:,:] = ''
  styles.loc[:, ('Sat', 'Dinner')] = 'background-color: lightskyblue'
  return styles

cross.style.apply(highlight, axis=None)

cross_highlight_column.png

特定の要素(行と列を指定)

def highlight(df):
  styles = df.copy()
  styles.loc[:,:] = ''
  styles.loc[('Male', 'No'), ('Sat', 'Dinner')] = 'background-color: orange'
  return styles

cross.style.apply(highlight, axis=None)

cross_highlight_cell.png

各行の中の最大値

def highlight(s):
    # `is_max`は、最大の要素が`True`のSeriesです。
    # 例えば1行目は`[False, False, False, False, False, True]`になります。
    is_max = s >= s.max()
    styles = is_max.map(lambda x: 'background-color: mediumslateblue; color: white' if x else '')
    return styles

# `axis=columns`にすることで、列方向に各行に`highlight`を適用します。
# 各行はSeries型です。
cross.style.apply(highlight, axis='columns')

cross_highlight_row_max.png

各列の中の最大値

# `axis=index`にすることで、行方向に各列に`highlight`を適用します。
# 各列はSeries型です。
cross.style.apply(highlight, axis='index')

cross_highlight_column_max.png

行同士で比較

('Female', 'No')と行('Female', 'Yes')を比較して、大きい方を色付けする例です。

def highlight(s):
    colors = [None] * len(s)

    if s[('Female', 'No')] > s[('Female', 'Yes')]:
        # s.index.get_locで行番号を取得してスタイルを設定します。
        loc = s.index.get_loc(('Female', 'No'))
        colors[loc] = 'yellow'
    elif s[('Female', 'No')] < s[('Female', 'Yes')]:
        loc = s.index.get_loc(('Female', 'Yes'))
        colors[loc] = 'tomato'

    return ['' if c is None else 'background-color: {}'.format(c) for c in colors]

cross.style.apply(highlight, axis='index')

cross_highlight_compare.png


明日は @shotasakamoto さんです。お楽しみに!

12
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
14