pandas – テーブルのスタイル変更 まとめ

目次

概要

Excel の条件付き書式による色分けを pandas で実現する方法をまとめました。

スタイルを適用する範囲を設定する

特定の列

In [1]:
import numpy as np
import pandas as pd
from IPython.display import display, HTML

df = pd.DataFrame(
    [[0, 1, 2], [3, 4, 5], [6, 7, 8]], index=["a", "b", "c"], columns=["A", "B", "C"],
)
css = {"background-color": "green"}

# A 列
display(df.style.set_properties(subset="A", **css))

# A 列と C 列
display(df.style.set_properties(subset=["A", "C"], **css))

# A ~ C 列
display(df.style.set_properties(subset=pd.IndexSlice[:, "A":"B"], **css))
A B C
a 0 1 2
b 3 4 5
c 6 7 8
A B C
a 0 1 2
b 3 4 5
c 6 7 8
A B C
a 0 1 2
b 3 4 5
c 6 7 8

特定の行

In [2]:
# a 行
display(df.style.set_properties(subset=pd.IndexSlice["a", :], **css))

# a 行と c 行
display(df.style.set_properties(subset=pd.IndexSlice[["a", "c"], :], **css))

# a 行 ~ c 行
display(df.style.set_properties(subset=pd.IndexSlice["a":"b", :], **css))
A B C
a 0 1 2
b 3 4 5
c 6 7 8
A B C
a 0 1 2
b 3 4 5
c 6 7 8
A B C
a 0 1 2
b 3 4 5
c 6 7 8

複数のスタイルを適用する場合

Styler オブジェクトの関数は返り値として Styler オブジェクトを返すので、複数のスタイルを適用する場合は連続して呼び出します。

In [3]:
style = df.style.set_properties(**{"background-color": "gray"})
style = style.set_properties(**{"color": "white"})

style
A B C
a 0 1 2
b 3 4 5
c 6 7 8

セルの強調表示ルール

値に応じて強調する

内容 条件の例
次の値の間 lambda x: 3 <= x <= 5
次の値の間以外 lambda x: not 3 <= x <= 5
次の値に等しい lambda x: x == 3
次の値に等しくない lambda x: x != 3
次の値より大きい lambda x: x > 3
次の値より小さい lambda x: x < 3
次の値以上 lambda x: x >= 3
次の値以下 lambda x: x <= 3
In [4]:
df = pd.DataFrame(
    [
        [11, 0, 15, 4, 5],
        [2, 12, 10, 8, 16],
        [17, 24, 14, 13, 23],
        [19, 6, 18, 2, 7],
        [3, 9, 20, 21, 1],
    ],
    index=["a", "b", "c", "d", "e"],
    columns=["A", "B", "C", "D", "E"],
)

css = "background-color: green"
df.style.where(lambda x: x == 2, css, "")
A B C D E
a 11 0 15 4 5
b 2 12 10 8 16
c 17 24 14 13 23
d 19 6 18 2 7
e 3 9 20 21 1

重複する値を強調する

In [5]:
df = pd.DataFrame(
    [[1, 2, 1], [1, 3, 2], [2, 3, 3],], index=["a", "b", "c"], columns=["A", "B", "C"]
)

css = "background-color: green"


def highlight_duplicated(s):
    return [css if x else "" for x in s.duplicated(keep=False)]


# 列ごと見たとき、重複している値を強調する
display(df.style.apply(highlight_duplicated, axis=0))

# 行ごと見たとき、重複している値を強調する
display(df.style.apply(highlight_duplicated, axis=1))
A B C
a 1 2 1
b 1 3 2
c 2 3 3
A B C
a 1 2 1
b 1 3 2
c 2 3 3

一意な値を強調する

In [6]:
df = pd.DataFrame(
    [[1, 2, 1], [1, 3, 2], [2, 3, 3],], index=["a", "b", "c"], columns=["A", "B", "C"]
)

css = "background-color: green"


def highlight_unique(s):
    return ["" if x else css for x in s.duplicated(keep=False)]


# 列ごと見たとき、一意な値を強調する
display(df.style.apply(highlight_unique, axis=0))

# 行ごと見たとき、重一意な値を強調する
display(df.style.apply(highlight_unique, axis=1))
A B C
a 1 2 1
b 1 3 2
c 2 3 3
A B C
a 1 2 1
b 1 3 2
c 2 3 3

値の順位に応じて強調する

In [7]:
df = pd.DataFrame(
    [
        [11, 0, 15, 4, 5],
        [2, 12, 10, 8, 16],
        [17, 24, 14, 13, 23],
        [19, 6, 18, 2, 7],
        [3, 9, 20, 21, 1],
    ],
    index=["a", "b", "c", "d", "e"],
    columns=["A", "B", "C", "D", "E"],
)

css = "background-color: green"


def highlight_topk(s, n):
    return [css if x <= n else "" for x in s.rank(ascending=False)]


def highlight_bottomk(s, n):
    return [css if x <= n else "" for x in s.rank(ascending=True)]


def highlight_topk_percentile(s, q=0.9):
    q = s.quantile(q)
    return [css if x >= q else "" for x in s]


def highlight_bottomk_percentile(s, q=0.1):
    q = s.quantile(q)
    return [css if x <= q else "" for x in s]


# 上位2個
display(df.style.apply(highlight_topk, n=2))

# 下位2個
display(df.style.apply(highlight_bottomk, n=2))

# 上位10%
display(df.style.apply(highlight_topk_percentile, axis=0))

# 下位10%
display(df.style.apply(highlight_bottomk_percentile, axis=0))
A B C D E
a 11 0 15 4 5
b 2 12 10 8 16
c 17 24 14 13 23
d 19 6 18 2 7
e 3 9 20 21 1
A B C D E
a 11 0 15 4 5
b 2 12 10 8 16
c 17 24 14 13 23
d 19 6 18 2 7
e 3 9 20 21 1
A B C D E
a 11 0 15 4 5
b 2 12 10 8 16
c 17 24 14 13 23
d 19 6 18 2 7
e 3 9 20 21 1
A B C D E
a 11 0 15 4 5
b 2 12 10 8 16
c 17 24 14 13 23
d 19 6 18 2 7
e 3 9 20 21 1

データバー

In [8]:
df = pd.DataFrame(
    {
        "A": [132, -107, -162, 96, 145, -133, 12, 35, 168, -12],
        "B": [0, -143, 21, 10, 105, 56, 120, 103, -132, 63],
        "C": [-31, 56, 67, 0, 16, 139, 0, -38, 142, -58],
    }
)

df.style.bar(color=["red", "green"], align="mid")
A B C
0 132 0 -31
1 -107 -143 56
2 -162 21 67
3 96 10 0
4 145 105 16
5 -133 56 139
6 12 120 0
7 35 103 -38
8 168 -132 142
9 -12 63 -58

カラースケール

In [9]:
df.style.background_gradient()
A B C
0 132 0 -31
1 -107 -143 56
2 -162 21 67
3 96 10 0
4 145 105 16
5 -133 56 139
6 12 120 0
7 35 103 -38
8 168 -132 142
9 -12 63 -58

書式

小数点以下の桁数

In [10]:
df = pd.DataFrame(
    [
        [0.38, 0.51, 0.19, 0.79, 0.38],
        [0.0, 0.75, 0.85, 0.33, 0.87],
        [0.66, 0.76, 0.0, 0.61, 0.5],
        [0.94, 0.16, 0.28, 0.07, 0.82],
        [0.73, 0.04, 0.14, 0.24, None],
    ],
    index=["a", "b", "c", "d", "e"],
    columns=["A", "B", "C", "D", "E"],
)

df.style.set_precision(2)
A B C D E
a 0.38 0.51 0.19 0.79 0.38
b 0.00 0.75 0.85 0.33 0.87
c 0.66 0.76 0.00 0.61 0.50
d 0.94 0.16 0.28 0.07 0.82
e 0.73 0.04 0.14 0.24 nan

パーセント表示

In [11]:
df.style.format("{:.0%}")
A B C D E
a 38% 51% 19% 79% 38%
b 0% 75% 85% 33% 87%
c 66% 76% 0% 61% 50%
d 94% 16% 28% 7% 82%
e 73% 4% 14% 24% 82%

欠損値の表記

In [12]:
df.style.format("{:.0%}", na_rep="-")
A B C D E
a 38% 51% 19% 79% 38%
b 0% 75% 85% 33% 87%
c 66% 76% 0% 61% 50%
d 94% 16% 28% 7% 82%
e 73% 4% 14% 24%

列の幅

In [13]:
df = pd.DataFrame(
    [
        [0.38, 0.51, 0.19, 0.79, 0.38],
        [0.0, 0.75, 0.85, 0.33, 0.87],
        [0.66, 0.76, 0.0, 0.61, 0.5],
        [0.94, 0.16, 0.28, 0.07, 0.82],
        [0.73, 0.04, 0.14, 0.24, None],
    ],
    index=["a", "b", "c", "d", "e"],
    columns=["A", "B", "C", "D", "E"],
)

# 各列の幅
widths = {"A": "60px", "B": "70px", "C": "80px", "D": "90px", "E": "100px"}

style = df.style.set_precision(2)
for col, width in widths.items():
    style = style.set_properties(subset=col, **{"width": width})
style
A B C D E
a 0.38 0.51 0.19 0.79 0.38
b 0.00 0.75 0.85 0.33 0.87
c 0.66 0.76 0.00 0.61 0.50
d 0.94 0.16 0.28 0.07 0.82
e 0.73 0.04 0.14 0.24 nan

CSS をカスタマイズする

  • set_properties(): 各セルに一律に適用する CSS
  • set_table_styles(): 各セルに個別に適用する CSS
In [14]:
df = pd.read_csv("https://git.io/JJlHw")

table_css = [
    # ヘッダの CSS
    {
        "selector": "th",
        "props": [
            ("background-color", "#00557F"),
            ("color", "white"),
            ("border", "1px solid #006699"),
        ],
    },
    # ボディの CSS
    {
        "selector": "td",
        "props": [
            ("background-color", "#E1EEF4"),
            ("color", "#00557F"),
            ("border", "1px solid #006699"),
        ],
    },
]

style = df.head().style
style = style.set_precision(2).set_table_styles(table_css)
style
total_bill tip sex smoker day time size
0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4

コメント

コメントする

目次