Help us understand the problem. What is going on with this article?

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

はじめに


unsplash-logoIcons8 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))

https://github.com/mwaskom/seaborn/blob/master/seaborn/distributions.py#L24

おわりに

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

matyubara
データ分析/機械学習/MLOps/データ可視化
https://booklog.jp/users/matyubara
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away