Matplotlib でヒストグラムを作成します

Matplotlib でヒストグラムを作成します

ヒストグラムの作成

 Axesオブジェクトの hist()メソッドを使うと、ヒストグラムを描くことができます。以下のサンプルコードでは、男性の身長の疑似統計データを作成してヒストグラムで可視化しています。

# https://python.atelierkobato.com/histgram/

# 男性の身長ヒストグラム

# NumPyとmatplotlib.pyplotをインポート
import numpy as np
import matplotlib.pyplot as plt

# Figureを作成
fig = plt.figure()

# グリッド線の表示
plt.style.use("ggplot")

# FigureにAxesを1つ追加
ax = fig.add_subplot(111)

# Axesのタイトルの設定
ax.set_title("Male Height Distribution", fontsize = 16)

# 軸ラベルの設定
ax.set_xlabel("Height", fontsize = 16)
ax.set_ylabel("Frequency", fontsize = 16)

# 正規分布にしたがうデータ(男性の平均身長)を作成
mu = 171
sigma = 5.7
x = np.random.normal(mu, sigma, size = 1000)

# Axesにヒストグラムを描画
ax.hist(x, color = "blue")

# グラフを描画
plt.show()

 男性の身長のヒストグラム

 サンプルコードの解説です。疑似データの作成には、numpy.random の normal()関数を使用しています。normal() は第 1 引数と第 2 引数で指定した平均値と標準偏差をもつ正規分布にしたがう乱数を返します。また、size でデータの個数を指定しています。上のサンプルコードでは最初に

# 平均値と標準偏差の設定
mu = 171
sigma = 5.7

と記述して平均値と標準偏差の値を明示しています。値を直接 normal() の引数に記述すればコードの行数は節約できますが、このように書いておけば、このデータを書き換えることによって異なる分布が描けることがすぐにわかります。

 次に numpy.random の seed()関数で乱数の seed値(種)を固定して、乱数ジェネレータを初期化しています:

# 乱数ジェネレータの初期化
np.random.seed(0)

 この記述によって、上のサンプルコードをコピーしたユーザーは同じデータを再現することができます(グラフも同じ形になるはずです)。

 先ほど設定した 平均値 mu と標準偏差 sigma, データの個数 1000 を normal()関数に渡してデータを作成します:

# 正規分布にしたがうデータ(男性の身長データ)を作成
x = np.random.normal(mu, sigma, size = 1000)

 Axesオブジェクトの hist()メソッドを使って、ヒストグラムを描きます(グラフの色は青に設定):

# Axesにヒストグラムを描画
ax.hist(x, color = "blue")

 

binの幅を調整します

 hist()メソッドのデフォルト設定では、bin (棒) 同士の間に隙間がなく、あまり見栄えがよくありません。そこで bin の幅を引数 rwidth で調整してみます。サンプルコードを次のように書き換えると隙間ができます。

# Axesにヒストグラムを描画
ax.hist(x, rwidth = 0.9, color = "blue")

 ヒストグラムの階級幅を小さく設定

 rwidth はデフォルトの幅を 1 とする相対的な値を渡します。rwidth = 0.9 ならデフォルト値の 90% の幅が指定されたことになります。
 

データを正規化して相対度数を表示させます

 デフォルト設定ではヒストグラムの縦軸は階級幅に入るデータ数を表しますが、このままではデータ数の異なる他のデータと比較することができません。引数 density に True を渡すとデータが正規化され、ヒストグラムの縦軸は相対度数を表すようになります:

# Axesにヒストグラムを描画
ax.hist(x, rwidth = 0.9, color = "blue", density = True)

 正規化されたヒストグラム

 以前は正規化する引数として normed がありましたが、現在では非推奨となり(今でも使えることは使えますが、いずれ廃止される可能性が高いです)、代わりに density を使用するように勧められています。上のグラフは、すべての bin の面積を足し合わせると 1 になるように調整されています (個々の bin の面積は [階級幅] × [頻度])。
 

複数のヒストグラムを重ねます

 Axesオブジェクトの hist()メソッドに繰り返し引数が渡されると、Axes に複数のヒストグラムが重ねて表示されます。今度は男女の身長の疑似統計データを作成してヒストグラムを描いてみましょう。

# https://python.atelierkobato.com/histgram/

# 身長ヒストグラム

# NumPyとmatplotlib.pyplotをインポート
import numpy as np
import matplotlib.pyplot as plt

# Figureを作成
fig = plt.figure()

# グリッド線の表示
plt.style.use("ggplot")

# FigureにAxesを1つ追加
ax = fig.add_subplot(111)

# Axesのタイトルの設定
ax.set_title("Height Distribution", fontsize = 16)

# 軸ラベルの設定
ax.set_xlabel("Height", fontsize = 16)
ax.set_ylabel("Frequency", fontsize = 16)

# 男性(male)の身長の平均値と標準偏差の設定
mu_m = 171
sigma_m = 5.7

# 女性(female)の身長の平均値と標準偏差の設定
mu_f = 159
sigma_f = 5.2

# 乱数ジェネレータの初期化
np.random.seed(0)

# 正規分布にしたがう身長データを作成
x = np.random.normal(mu_m, sigma_m, size = 1000)
y = np.random.normal(mu_f, sigma_f, size = 1000)

# Axesにヒストグラムを描画
ax.hist(x, rwidth = 0.9, color = "blue",
label = "male", density = True)

ax.hist(y, rwidth = 0.9, color = "red",
label = "female", alpha = 0.6, density = True)

ax.legend(loc = "upper left")

# グラフを描画
plt.show()

 男女の平均身長のヒストグラムを重ねて描画

 最初のサンプルとほぼ同じ構造のコードですが、今回はそれぞれのヒストグラムが何を表しているのかを識別するためにデータの凡例(ラベル)を添えています。凡例として表示する文字は hist メソッドの label 引数で指定し、その表示位置は legend()メソッドの loc 引数に渡します。サンプルコードでは "upper left" (左上) に表示させています:

# Axesにヒストグラムを描画
ax.hist(x, rwidth = 0.9, color = "blue",
label = "male", density = True)

ax.hist(y, rwidth = 0.9, color = "red",
label = "female", alpha = 0.6, density = True)

ax.legend(loc = "upper left")

 ヒストグラムが重なると後ろのデータが見えなくなってしまうので、手前に表示される女性のヒストグラムは alpha 引数を指定して半透明にしてあります。