Chapter 05

Seabornでヒストグラムを作る

mimitako
mimitako
2022.10.09に更新

ヒストグラムの作り方

ヒストグラムは連続データを任意の区間に切り分けて、その区間における数または割合をグラフ化するものです。身長であれば〇〇 ~ △△cm が xx 人という形で区切りデータ全体を見えるようにします。

まずは見てみる

seaborn でヒストグラムがどのように表されるのか見てみましょう。今回も Iris のデータセットを利用します。

モジュールのインポート

使い始める前にいくつかのモジュールをインポートしておきます。

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd

データセットのインポート

今回使用するデータは iris(あやめ)のデータセットです。

iris_data = sns.load_dataset("iris")

データ構造は次の通りです。

sepal length はがくの長さ、sepal width はがくの幅、petal length は花びらの長さ、petal width は花びらの幅です。species は iris ことあやめの種類を示しています。

ヒストグラムを描写する

ヒストグラムは sns.histplot()で描画できます。具体的には次のように記述します。

fig, ax = plt.subplots(1,1,dpi = 300)
ax = sns.histplot(
  data = iris_data,
  x = "sepal_width"
)
ax.set_xlabel("sepal width")
ax.set_ylabel("count")
ax.set_title("Histgram of iris sepal width")

結果はこちらです。

このように、どれくらいの値が多く存在しているかを人目で確認することができます。

ヒストグラムを比べる

ヒストグラムの色は引数 color を指定することで任意の色を設定できます。また、alpha を 0~1 の間で設定することにより、透明度を指定できます。

これらを利用して複数のグラフを重ねて表示することにより、違いをもっとわかりやすくできます。

fig, ax = plt.subplots(1,1,dpi = 300)
ax = sns.histplot(
  data = iris_data,
  x = "sepal_width",
  color="b",
  alpha = 0.3,
)
ax = sns.histplot(
  data = iris_data,
  x = "sepal_length",
  color="r",
  alpha = 0.3,
)

ax.set_xlabel("length")
ax.set_ylabel("count")
ax.set_title("Histgram of iris")

これを描写すると下記のようになります。

列単位で比較する場合はこの方法が楽です。凡例を付ける場合は hue を設定する必要がありますのでデータ構造を変更する必要があります。

では、次に凡例の表示をするためにがくの幅を花の種類ごとに比べてみます。

fig, ax = plt.subplots(1,1,dpi = 300)
ax = sns.histplot(
  data = iris_data,
  x = "sepal_width",
  hue="species",
  palette="winter",
  alpha = 0.3,
)
ax.set_xlabel("sepal width")
ax.set_ylabel("count")
ax.set_title("Histgram of iris")

hue を設定した場合、凡例が表示されます。グラフが完全に重なった場合は少し分かりづらいですね。もう少し工夫するために、kde(カーネル密度分布)を表示してみます。

ax = sns.histplot(
  data = iris_data,
  x = "sepal_width",
  hue="species",
  palette="winter",
  alpha = 0.3,
  kde = True # これを追加する
)

実際の表示はこちらです。

このように setosa が他の 2 種類よりもずれていることがひと目でわかります。もしカーネル密度関数だけで良い場合は kdeplot と呼ばれる関数が別途設定されていますのでそれを利用しましょう。

fig, ax = plt.subplots(1,1,dpi = 300)
ax = sns.kdeplot(
  data = iris_data,
  x = "sepal_width",
  hue="species",
  palette="winter",
  alpha = 0.7,
)
ax.set_xlabel("sepal width")
ax.set_ylabel("ratio")
ax.set_title("KDE of iris")

グラフの幅を調整する

ヒストグラムは幅(bin の数)を変化させるだけで見た目が大きく変わります。正解はないとされていますが、ある程度の規則は維持しておきたいものです。そのときに利用するのがスタージェスの公式と呼ばれるもので

階級の数 = 1 + \log_2 n

で表されます。とは言え、せっかくですので今回は幅を変えることで見栄えがどんな変化をするのか見てみましょう。今回は 5 ~ 9 までの変化をさせた場合について見てみます。5 が青色、9 が紫色です。

結果はこの様になり、x 軸の分割数が増えるごとに count が減っていき、きれいな山なりのグラフができてくることがわかります。

さらに分割数を 5, 10, 20 とした場合の極端な例を作成してみます。

やはり明らかに見た目が変わりますね。bins の指定がうまくできていない場合は検討がうまくできないこともあります。注意して選択したいですね。

スタージェスの公式を利用する

せっかくですから最初に出てきたスタージェスの公式を利用して見ましょう。

import numpy as np # numpyでいくつか計算します。
#np.ceilでは小数点の切り上げを実施します。
#len(DataFrame)で行数を取得します。

bin_count = int(1 + np.ceil(np.log2(len(iris_data.sepal_width))))
print (bin_count) # 9

fig, ax = plt.subplots(1,1,dpi = 300)

ax = sns.histplot(
  data = iris_data,
  x = "sepal_width",
  bins = bin_count,
  color = "b",
  alpha = 0.3,
)
ax.set_xlabel("sepal width")
ax.set_ylabel("count")
ax.set_title("Histgram of iris sepal width")

一番キレイにヒストグラムを表示できている気がしますね。これがすべてに置いて正解とは限りませんが、困ったときは一度試してみる価値があります。