LoginSignup
6
9

More than 3 years have passed since last update.

matplotlibやseabornのヒストグラムでビン幅をサクッとキレイに整える

Last updated at Posted at 2020-03-03

はじめに


Icons8 Team

ラベル別にデータの分布を確認するためヒストグラムを重ねてプロットすることは多いが、データ次第ではビン幅の違いが目立つケースがある。
TableauをはじめとしたBIツールを使っていても発生しないが、matplotlibやseabornは勝手に調整してくれないので自分で対応する必要がある。

方法

引数のbinsを利用する。

bins : int or sequence or str, optional
matplotlib.pyplot.hist

binsは整数値だけでなくsequenceも受け取れるので、
range関数に最大値最小値を指定して好みの分割数を設定するだけでいい。


import numpy as np
import matplotlib.pyplot as plt

# ラベルが2種類でデータの分布が異なるDataFrameを用意
df_1st = pd.DataFrame(np.random.normal(loc=20, scale=10, size=100), columns=["val"])
df_1st["target"] = "class_1"
df_2nd = pd.DataFrame(np.random.normal(loc=15, scale=20, size=100), columns=["val"])
df_2nd["target"] = "class_2"

df = pd.concat([df_1st, df_2nd])

ビン幅補正前

import matplotlib as plt
import seaborn as sns

# target毎にプロット
for val in df["target"].unique():
    ax = sns.distplot(df.query('target == @val')["val"], kde=False, label=f"target is {val}")

ax.legend()

ビン幅補正後

# 最小値
x_min = int(df["val"].min())

# 最大値
x_max = int(df["val"].max())

# 最小値から最大値の範囲で5間隔
range_bin_width = range(x_min, x_max, 5)

# target毎にプロット
for val in df["target"].unique():
    ax = sns.distplot(df.query('target == @val')["val"], bins=range_bin_width, kde=False, label=f"target is {val}")

ax.legend()

補足

binsを設定しない場合、Freedman-Diaconis ruleと呼ばれる手法でビンの数が決定されている。
この手法は中々優秀で単一のデータをプロットする場合、概ね問題なくプロットされる。

distributions.py
def _freedman_diaconis_bins(a):
    """Calculate number of hist bins using Freedman-Diaconis rule."""
    # From https://stats.stackexchange.com/questions/798/
    a = np.asarray(a)
    if len(a) < 2:
        return 1
    h = 2 * iqr(a) / (len(a) ** (1 / 3))
    # fall back to sqrt(a) bins if iqr is 0
    if h == 0:
        return int(np.sqrt(a.size))
    else:
        return int(np.ceil((a.max() - a.min()) / h))

おわりに

プロットは美しくないプロットは見せる相手に失礼なので、
最低限キレイに整えるするのは礼儀だと思う。

6
9
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
6
9