# (必須)モジュールのインポート
import os
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt

# 表示設定
np.set_printoptions(suppress=True, precision=3)
pd.set_option('display.precision', 3)    # 小数点以下の表示桁
pd.set_option('display.max_rows', 50)   # 表示する行数の上限
pd.set_option('display.max_columns', 5)  # 表示する列数の上限
%precision 3
'%.3f'

5. Matplotlibの基礎#

本章は主に以下の文献とウェブサイトを参考にしている:

  • Jake VanderPlas, Pythonデータサイエンスハンドブック,オライリー,2018

  • 橋本洋志,牧野浩二,Pythonコンピュータシミュレーション入門,オーム社,2021.

  • note.nkmk.me

  • YutaKaのPython教室 > Matplotlib

以下のMatplotlib公式ギャラリーには様々なグラフとそのコードがまとまっている. この中から作成したい図に近いものを見つけ,コードを参考にすると良い.

※ 一番最後のコマンドにセミコロンを付けることがある.これは,Jupyter上に不要な文字列が出力されるのを防ぐ(隠す)ためである.

5.1. Matplotlibの基本操作#

5.1.1. Matplotlibのインポート#

Matplotlibは以下のようにインポートするのが慣例である.

import matplotlib as mpl
import matplotlib.pyplot as plt

5.1.2. プロットの基本#

Matplotlibの最も基本的なプロット関数がplt.plot(以下,単にplotメソッド)である. プロットには2つのスタイルが存在するが,本講義ではオブジェクト指向スタイルを採用する(詳細は 2つのプロットスタイル を参照). オブジェクト指向スタイルでは,FigureオブジェクトとAxesオブジェクトを生成した上で以下のように実行する.

fig, ax = plt.subplots(figsize=(3, 3))
ax.plot([0, 1, 2, 3], [1, -1, 1, -1], 'bx-');
../_images/97afb1020a58e516c00bdc3832c2abff78c512fd822a2130925966f8e38a6097.png
  • 第1引数:\(x\) 座標のデータをリストやNumPy配列で指定する

  • 第2引数:\(y\) 座標のデータをリストやNumPy配列で指定する

  • (省略可)第3引数:色・マーカー・線種を'bx-'のように同時に指定する.この場合は青のマーカー'x'をプロットし,それらを実線で結ぶ.

5.1.3. グラフ作成の一連の流れ#

データのプロット,グラフの装飾,グラフの保存までの一連の流れは以下の通りである.

# FigureとAxesを生成する
fig, ax = plt.subplots(figsize=(4, 3))

# Axesに対してプロットする
x = np.linspace(0, 2*np.pi, 20)
ax.plot(x, np.cos(x), '-')   # 折れ線
ax.plot(x, np.sin(x), 'rx')  # 赤のo
ax.plot(x, 2*np.sin(x), 'bo--');  # 青のoを点線で結ぶ

# Axesを装飾する
ax.set_xlim(0, 2*np.pi); ax.set_ylim(-2.1, 2.1)
ax.set_xlabel('X'); ax.set_ylabel('Y')

# Figureを保存する(相対パスを指定)
fig.savefig('./sample_graph.pdf', bbox_inches="tight", pad_inches=0.2, transparent=True, dpi=300)
../_images/51a3cb1d89bc7c668eb2a0e9426d2b87697fc742111380b7c75ebfd73be35bb2.png

5.2. 様々なグラフ#

5.2.1. 基本のプロット関数#

Matplotlibの最も基本的なプロット関数がplotメソッドである. Axesオブジェクトをaxとして取得した場合は以下のように実行する:

ax.plot(x, y, 'rx-', option)

plotメソッドの第3引数は色・マーカー・線種を同時指定することができる. それ以外の主要なoptionを以下にまとめる.

オプション名

省略表記

内容

指定の仕方(例)

color

c

'k'(='black'), 'r'(='red'), 'b'(='blue')

linestyle

ls

線種

'-', '--', ':' , '-.', 'None'

marker

なし

マーカーの種類

'x', 'o', '^', '.', '+', 's', 'd'

markersize

ms

マーカーのサイズ

数値

markeredgecolor

mec

マーカーの境界の色

色名

markerfacecolor

mfc

マーカーの塗りつぶしの色

色名

linewidth

lw

線の太さ

数値

alpha

なし

透過度

0~1

色の指定

  • color='red'のように色名で指定する.

  • 'red','green','blue','black','white','yellow','magenta','cyan'は'r'のように頭文字だけで指定できる.

  • 他の色名はここにまとまっている.

  • 色を指定しない場合はデフォルトの色から順に指定される.

# 様々な色の指定方法
fig, ax = plt.subplots(figsize=(3, 3))
x = np.arange(0, 10)
ax.plot(x, x, 'red')  # 第3引数に色名を指定
ax.plot(x, x+1, 'g')  # 第3引数に色名の頭文字を指定
ax.plot(x, x+2, color='blue') # colorオプションに色名を指定
ax.plot(x, x+3, c='k'); # colorオプションに色名の頭文字を指定
../_images/63847d8a19cc0ab6b2b047a334cca649c3e2f80225adb32dd7f56a5a44f24030.png

マーカーの指定

  • marker='x'のように指定する

  • 主要なマーカーは'x', 'o', '^', '.', '+', 's', 'd'

  • 他のマーカーはここにまとまっている

  • マーカーを指定しない場合はデフォルトのマーカーが順に指定される

# 様々なマーカー
fig, ax = plt.subplots(figsize=(3, 3))
x = np.arange(0, 10)
ax.plot(x, x, 'x', ms=10)   # 第3引数にマーカーを指定し,サイズを10に変更
ax.plot(x, x+1, '.', ms=3)
ax.plot(x, x+2, '+', ms=5)
ax.plot(x, x+3, marker='o', ls='None', mfc='None')
ax.plot(x, x+4, marker='^', ls='None', mfc='None', mec='b');
../_images/2366f8c51ca653987bd0d883da10a5a499b17fb9bbd24e33f91043d17de1dd53.png

線種の指定

  • linestyle='-'のように指定する

  • 主要な線種:'-', '--', ':' , '-.', 'None'

# 様々な線種
fig, ax = plt.subplots()
x = np.arange(0, 10)
ax.plot(x, x, '-')
ax.plot(x, x+1, linestyle='--')
ax.plot(x, x+2, ls=':')
ax.plot(x, x+3, ls='-.');
../_images/8548526181b69e32ba6023fb884af627d853a414f882fc4ba98e4ae837b1656d.png

5.2.2. 棒グラフ#

fig, ax = plt.subplots()

x = np.arange(5)
h = np.arange(1, 6, 1)
ax.bar(x, h, width=0.2, align='edge', color='w', edgecolor='b');
../_images/6015349712b6d95a9fac19dac47a9a33b87e59590073b94be6551e0f32b095c7.png
  • 棒グラフを描くにはbarメソッドを用いる.

  • 第1引数xには棒グラフを出力する\(x\)軸上の位置,第2引数h には高さを指定する.

  • その他のオプションはここにまとまっている.

5.2.3. 矢印#

# 2つの矢印
X = [0, 1]
Y = [0, 2]
U = [1, 2]
V = [2, 0.5]

fig, ax = plt.subplots()
ax.quiver(X, Y, U, V, angles='uv', units='xy', scale=1, width=0.1)
ax.set_xlim([0, 3]); ax.set_ylim([0, 3])
ax.set_aspect('equal');
../_images/cedb4bc0654719f1dd9fba217d70b9617e1f91a58c883be2289eb56d9960fe56.png
  • 矢印を描くには,quiverメソッドを用いる.

  • 始点 \((x, y)\) から \((u, v)\) の方向に長さ\(\sqrt{u^2 + v^2}\)の矢印を描く

  • ただし,必ずアスペクト比を'equal'に変更しないと見た目がずれる.

  • 'angles','units','scale'などは挙動が分かりにくいので,詳しくはここを参照のこと.

5.3. グラフの装飾#

グラフを装飾するにはax.メソッド名のように装飾メソッドを呼び出す. 以下に主要なメソッドを用いたグラフ装飾の例を示す.

'''FigureとAxesの生成'''
fig, ax = plt.subplots(figsize=(5, 3))

'''Axesに対する描画'''
x = np.linspace(0, 10, 30)
ax.plot(x, np.sin(x), '-', label='A')
ax.plot(x, np.sin(x-np.pi/2), 'x-.', label='B')
ax.plot(x, np.sin(x-2*np.pi/2), '^--', label='C')

''' Axesの装飾 '''
# 座標軸の範囲の設定
ax.set_xlim(0, 10)
ax.set_ylim(-3, 3)

# アスペクト比
ax.set_aspect('equal')

# タイトル
ax.set_title('Sin Plots', fontsize=12)

# 軸ラベル
ax.set_xlabel('Angle $X$ [rad]', fontsize=12)
ax.set_ylabel('$Y$', fontsize=12)

# 凡例
ax.legend(loc='best', frameon=True, fontsize=8, numpoints=1)

# 補助目盛りの表示
ax.minorticks_on()

# 目盛線の表示
ax.grid(axis='both', which='major', linestyle='--')

# 目盛りラベルを文字列に変更
ax.set_xticks([0, np.pi, 2*np.pi, 3*np.pi])
ax.set_xticklabels(['0', '$\pi$', '$2\pi$', '$3\pi$'])

# 目盛りのラベルサイズ
ax.tick_params(axis='both', labelsize=12)

'''Figureの保存'''
fig.savefig('./multiple_sin_plots.pdf', bbox_inches='tight');
../_images/4bee6b6f176962617eb302150faac686ab847acfda2ca4d01da3c53e39223e22.png

座標軸の範囲

ax.set_xlim(0, 10)
ax.set_ylim(-3, 3)
  • 第1,第2引数には表示範囲の最小値と最大値を指定する.

アスペクト比

ax.set_aspect('equal')
  • 図の縦横比をアスペクト比と呼ぶ.

  • デフォルトではアスペクト比が自動調整されてしまうので,円が楕円に見えるなど,出力結果が歪んでしまう.

  • アスペクト比が \(y\) 軸の範囲と \(x\) 軸の範囲の比となるように設定するにには以下を実行する:

タイトルと軸ラベル

ax.set_title('三角関数のグラフ', fontsize=15)
ax.set_xlabel('角度 $X$ [rad]', fontsize=15)
ax.set_ylabel('$Y$', fontsize=15)
  • 第1引数にラベル名を指定する.

  • 第2引数以降にfontsizeなどのoptionを指定する.

凡例の追加

ax.plot(x, np.sin(x), '-', label='A')
ax.legend(numpoints=1, loc='best', frameon=True)
  • まず,plotメソッドのlabel引数で表示したいラベル名を指定する.

  • その上で,以下のようにax.legend(option)を実行する.

  • 主要なoptionを以下に示す

オプション

内容

指定の仕方(例)

loc

凡例の位置

'best', 'upper left', 'center', 'lower right'

fontsize

文字の大きさ

数値

frameon

枠で囲う

True / False

numpoints

マーカーの数

数値

5.3.1. 目盛り線の表示#

ax.grid(axis='both', which='major', linestyle='--')
  • 第1引数に1または0を指定することで,表示/非表示を選択できる.

  • より細かく制御したい場合はaxis引数とwhich引数を指定する.

    • axis引数は'x', 'y', 'both'を指定することで線を引く軸を設定できる.

    • which引数は'major', 'minor', 'both'を指定することで線を引く目盛りの種類(主目盛りと補助目盛り)を設定できる.

5.3.2. 目盛りラベル#

ax.set_xticks([0, np.pi, 2*np.pi, 3*np.pi])
ax.set_xticklabels(['0', '$\pi$', '$2\pi$', '$3\pi$'])
ax.tick_params(axis='both', labelsize=12)
  • 第1引数に目盛りを表示したい位置をリストで指定する.

  • デフォルトでは,目盛りに数値が表示されるが,これを任意の文字列に変更するにはax.set_xticklabelsを使用する.

  • 目盛りラベルの文字サイズを変更するにはax.tick_paramsを使用する.

5.3.3. 演習問題#

三角関数のグラフ

上の三角関数のグラフについて,各コマンドの条件を変えてグラフがどのように変わるか試してみよ.

2次関数のグラフ

以下の2次関数のグラフを指定した条件で作成せよ

\[ f(x) = -0.2(x-1)^2 + 2 \]
  • 上の2次関数を点線でプロットする

  • 頂点の位置に赤のxマーカーをプロットする

  • \(x\)軸の範囲:\(-10\le x\le 10\)

  • \(y\)軸の範囲:\(-5\le x\le 3\)

  • \(x\)軸に好きなラベルを設定する

  • \(y\)軸に好きなラベルを設定する

  • グラフを好きな名前で保存

# 解答欄

ポアソン分布のグラフ(得点分布への導入)

パラメータ \( \mu \) のポアソン分布は以下で定義される:

\[ f(x) = \frac{\mu^x}{x!} \mathrm{e}^{-\mu x} \]
  • Pythonにおいてポアソン分布を扱うには,まずscipy.stats.poissonをインポートする.

  • その上で,値 \(x\) に対してパラメータ \( m \) のポアソン分布を計算するには poisson.pmf(x, m) とする.

from scipy.stats import poisson
x = np.arange(0, 10)
poisson.pmf(x, 5)
array([0.007, 0.034, 0.084, 0.14 , 0.175, 0.175, 0.146, 0.104, 0.065,
       0.036])

ポアソン分布のグラフを以下の条件で作成せよ:

  • \(\lambda=1,4,10\)のポアソン分布を重ね書きする

  • \(\lambda\)の値ごとに異なるマーカーを用い,マーカー間は線で結ぶ

  • \(x\) 軸の範囲:\(0\le x \le 20\)

  • \(y\) 軸の範囲:\(0 \le y \le 0.4\)

  • \(x\)軸に好きなラベルを設定する

  • \(y\)軸に好きなラベルを設定する

  • 凡例を表示する

  • グラフを好きな名前で保存する

# 解答欄

選手の位置と速度ベクトルの描画

以下の条件で,グラフを作成せよ:

  • 以下の座標にマーカーをプロットする:

    X: 60.0, 22.2, 28.4, 33.7, 21.1, 22.1, 32.7, 18.3, 24.2, 64.3
    Y: 31.2, 27.3, 25.7, 28.0, 35.3, 15.0, 15.9, 19.4, 21.0, 26.1
    
  • 上の座標を始点として,以下のベクトルをプロットする:

    U: -3.1, -4.0, -1.9, -2.7, -2.9, -3.0, -1.0, -1.6, -0.0, -3.3
    V: -1.1, 1.6, 2.0, -0.0, -0.7, 1.3, 1.1, 1.5, 3.3, -0.8
    
    • scale=0.5width=0.5とする

  • \(x\) 軸の範囲:\(0\le x \le 105\)

  • \(y\) 軸の範囲:\(0 \le y \le 68\)

  • アスペクト比を1にする

# 解答欄

5.4. 箱ひげ図とヒストグラム#

データを取得したときに,まずは平均値,四分位数,分散・標準偏差などを求めてデータの分布をおおまかに把握するのがデータ分析の鉄則である. 既に説明したように,NumPyやPandasを用いれば,これらの要約統計量を手軽かつ高速に求めることができる. ここでは,データの分布を数量的に把握するだけでなく,Matplotlibを用いて可視化する方法を説明する. 具体的な可視化の方法として,以下の2つを扱う:

  1. 要約統計量を用いてデータのばらつきを可視化する箱ひげ図

  2. 直接的にデータの分布を可視化するヒストグラム

5.4.1. 箱ひげ図#

数値データを小さい順に並べたとき,中央に来るデータを中央値,下位半分のデータを下位データ,上半分のデータを上位データと呼ぶ. (※データ数が奇数個の場合には中央値を除いて半分に分ける.) また,下位データの中央値を第1四分位数,上位データの中央値を第3四分位数と呼ぶ. 最小値,第1四分位数,中央値,第3四分位数,最大値によってデータのばらつきを表す方法は五数要約と呼ばれる. (※データ数が偶数個の場合には,中央に来る2つの値の平均値を中央値とするのが一般的である.)

../_images/five_number.png

図 5.1 五数要約の例#

箱ひげ図とは,五数要約の結果を可視化した図のことである. 箱ひげ図は以下の手順で描く(テューキーの方式):

  1. データの第1四分位数から第3四分位数の間に箱を描く

  2. 中央値の位置に線を引く

  3. 箱から箱の幅(四分位範囲)の1.5倍を超えて離れた点を外れ値と見なし,白丸で描く.

  4. 外れ値でないものの最大値と最小値から箱まで線(ひげ)を引く.

../_images/box_plot.png

図 5.2 箱ひげ図の例#

Matplotlibで箱ひげ図を描くためにはax.boxplotメソッドを使う:

ax.boxplot([data1, data2, ...], option)
  • 第1引数に複数のデータを与えると,データごとの箱ひげ図を並べて表示することができる.

  • 主要なオプションは以下の通り(その他はここを参照).

オプション

内容

指定の仕方(例)

whis

箱の幅から何倍離れた点を外れ値と見なすか(デフォルトは1.5)

数値

widths

箱の幅

数値

vert

箱の回転

True/False

# データの作成
data1 = np.random.normal(loc=0, scale=1, size=100)
data2 = np.random.normal(loc=2, scale=2, size=100)
# 箱ひげ図のプロット
fig, ax = plt.subplots()
ret = ax.boxplot([data1, data2], whis=1.5, widths=0.5, vert=1)

# 横軸の目盛りラベル
ax.set_xticklabels(['data1', 'data2'])

# 軸のラベル
ax.set_xlabel('$X$', fontsize=15)
ax.set_ylabel('$Y$', fontsize=15);
../_images/bd42ca82ce3ec2f4fbc5beff933b5f359a503d8e21a4e0843dc9dd2a6eb029cc.png

PandasのDataFaremeには要約統計量を一度に計算するdescribeメソッドが用意されている. これを用いて,要約統計量を求めると以下のようになる.

df = pd.DataFrame({'data1':data1, 'data2':data2})
df.describe()
data1 data2
count 100.000 100.000
mean 0.003 2.130
std 0.909 1.716
min -2.601 -1.776
25% -0.575 1.018
50% 0.135 2.175
75% 0.574 2.987
max 1.694 6.305

5.4.2. 1次元ヒストグラム#

データの分布(ある値のデータがどのくらいあるか)を表す方法として,箱ひげ図ではデータを要約しすぎてしまい適切にその特徴を表せないことがある. そこで,より詳細に分布の傾向を可視化する方法として度数分布表やそれを可視化したヒストグラム(度数分布図)がある. 度数分布とは,値を0以上10未満,10以上20未満などのいくつかの区間(階級ビン)に分けてそれぞれの区間に含まれるデータの個数(度数)をまとめたもので,横軸に階級の代表値(階級値),縦軸に度数をとったグラフがヒストグラムである. なお,ヒストグラムの横軸には各階級の最小と最大を表示する場合や,階級の最小値や中央値を示す場合がある. また,縦軸には度数ではなく相対度数(度数/データ数)や累積度数(その階級までの度数の和)を取ることがある.

Matplotlibで1次元ヒストグラムを描画するにはax.hist()を用いる:

ax.hist(data, bins, option)
  • 第1引数には数値データを与える.

  • bins引数には階級の分け方を指定する.以下の方法がある:

    • bins=nとした場合,\( n \) 個の等間隔の階級に分ける.1つの階級の幅は (最大値-最小値) / n となる.

    • bins=[0, 1, 2, 3]とした場合,各階級の境界は[0, 1), [1, 2), [2, 3]となる(最後だけ右端を含むことに注意).

# データの作成
np.random.seed(20)
data = np.random.normal(170, 10, 1000)

# ヒストグラムの描画
fig, ax = plt.subplots()
# ret = ax.hist(data, bins=10, color='gray', edgecolor='k')  # binsに階級数10を指定する
ret = ax.hist(data, bins=[130, 140, 150, 160, 170, 180, 190, 200], color='gray', edgecolor='k')  # binsに階級の境界値を指定する

# 軸のラベル
ax.set_xlabel('$X$', fontsize=15)
ax.set_ylabel('Frequency', fontsize=15)
ax.set_xticks(np.arange(130, 210, 10));
../_images/a5333d98f5e8423c8f4c5099e0a716ed40e6d79fc11570b86656efbe5db2306c.png

以下は上のヒストグラムに対応する度数分布表である.

f, x = ret[0], ret[1]
df = pd.DataFrame(np.c_[x[:-1], x[1:], 0.5*(x[1:]+x[:-1]), f, f/len(data)],
          columns=['最小', '最大', '階級値', '度数', '相対度数'])
df
最小 最大 階級値 度数 相対度数
0 130.0 140.0 135.0 1.0 0.001
1 140.0 150.0 145.0 16.0 0.016
2 150.0 160.0 155.0 139.0 0.139
3 160.0 170.0 165.0 347.0 0.347
4 170.0 180.0 175.0 329.0 0.329
5 180.0 190.0 185.0 149.0 0.149
6 190.0 200.0 195.0 19.0 0.019

ヒストグラムの装飾

ax.histメソッドにも,色やスタイルを変更するためのオプションが多数用意されている. 主要なオプションを以下にまとめる.

オプション

内容

指定の仕方(例)

histtype

ヒストグラムのスタイル

'bar', 'step', 'stepfilled', 'barstacked'

color

塗りつぶしの色

色名

edgecolor

枠線の色

色名

linewidth

枠線の太さ

数値

linestyle

線種

'-', '--', '-.', ':'

rwidth

バーの幅

数値(0~1)

align

バーの中央を階級のどこに合わせるか

'left'(階級の左端), 'mid'(階級の中央=デフォルト), 'right'(階級の右端)

# データの作成
np.random.seed(20)
data = np.random.normal(170, 10, 1000) # 平均170,標準偏差10の正規分布に従うデータ

fig, ax = plt.subplots()
ret = ax.hist(data, 
              bins=[130, 140, 150, 160, 170, 180, 190, 200], # 階級の左端の値を指定する
              histtype='bar',  # ヒストグラムのスタイルを棒グラフに
              color='c',       # バーの色をシアンに
              edgecolor='w',   # バーの枠線の色を白に
              linewidth=0.5,   # バーの枠線の太さを1に
              linestyle='-',  # 枠線を実線に
              )

# 軸のラベル
ax.set_xlabel('$X$', fontsize=15)
ax.set_ylabel('Frequency', fontsize=15)
ax.set_xticks(np.arange(130, 210, 10));
../_images/8ace8cf1260d876e68bd91fd860d85c52e7a7e3ad310312cc6213b5a7da6970d.png

ヒストグラムのタイプ

densityオプションにより,ヒストグラムの縦軸を相対度数に変更することができる. また,cumulativeオプションにより,縦軸を累積度数に変更することができる.

オプション

内容

指定の仕方(例)

density

縦軸を相対度数に変更

True/False

cumulative

縦軸を累積度数に変更

1(下側累積), -1(上側累積)

# データの作成
np.random.seed(20)
data = np.random.normal(170, 10, 1000) # 平均170,標準偏差10の正規分布に従うデータ

fig, ax = plt.subplots()
ret = ax.hist(data, 
              bins=[130, 140, 150, 160, 170, 180, 190, 200], # 階級の左端の値を指定する
              density=1,      # 縦軸を相対度数に変更
              cumulative=-1,  # 上側累積に変更  
              histtype='bar', color='c', ec='w', lw=0.5, ls='-'
              )

# 軸のラベル
ax.set_xlabel('$X$', fontsize=15)
ax.set_ylabel('Relative Frequency', fontsize=15)
ax.set_xticks(np.arange(130, 210, 10));
../_images/c3b84a4c68922d1261e04ad268bc3f02f3575450f2eed9fc0b46a14b659b9589.png

5.4.3. 1次元ヒストグラムと確率分布の重ね書き#

正規分布

平均 \( \mu \),標準偏差 \( \sigma \) の正規分布は以下で定義される:

\[ f(x; \mu, \sigma) = \frac{1}{\sqrt{2\pi\sigma^2}} \mathrm{e}^{-\frac{(x-\mu)^2}{2\sigma^2}} \]

以下は \( \mu=180,\ \sigma=10 \) の正規分布に従うデータからヒストグラムを作成し,確率密度関数を重ね書きした例である.

# 正規分布に従うデータの生成
from scipy.stats import norm
np.random.seed(5)
data = norm.rvs(loc=180, scale=5, size=1000) # 平均180, 標準偏差5の正規分布に従うデータ
fig, ax = plt.subplots()

# 指数分布の確率密度関数を描画する
x = np.arange(160, 200, 0.1)
ax.plot(x, norm.pdf(x, loc=180, scale=5), 'r-', lw=1)

# ヒストグラムを描画する
ret = ax.hist(data, 
              bins=20, # 階級数を20に指定
              density=1,       # 縦軸を相対度数に変更
              histtype='bar',  # ヒストグラムのスタイルを棒グラフに
              color='c',       # バーの色をシアンに
              edgecolor='w',   # バーの枠線の色を白に
              linewidth=0.5,   # バーの枠線の太さを1に
              )

# 軸のラベル
ax.set_xlabel('$X$', fontsize=15)
ax.set_ylabel('Frequency', fontsize=15)
ax.set_xlim(160, 200); ax.set_ylim(0, 0.1);
../_images/b69f1e5a00e2c5a5da0d7b4bebc890efe2b50041908447c8c201bff692d67b3d.png

ポアソン分布

パラメータ \( \mu \) のポアソン分布は以下で定義される:

\[ f(x) = \frac{\mu^x}{x!} \mathrm{e}^{-\mu x} \]

以下はパラメータ \( \mu=2 \) のポアソン分布に従うデータからヒストグラムを作成し,確率質量関数を重ね書きした例である.

# ポアソン分布に従うデータの生成
from scipy.stats import poisson
np.random.seed(20)
data = poisson.rvs(mu=2, size=1000) # データの生成
fig, ax = plt.subplots()

# ポアソン分布の確率質量関数を描画する
x = np.arange(0, 10, 1)
ax.plot(x, poisson.pmf(x, 2), 'r-', lw=1)

# ヒストグラムを追加する
ret = ax.hist(data, 
              bins=np.arange(0, 10), # 階級の左端の値を指定する
              density=1,      # 縦軸を相対度数に変更
              align='left',   # バーの中央を階級の左端に合わせる
              histtype='bar', # ヒストグラムのスタイルを棒グラフに
              rwidth=0.3,     # バーの幅を0.8に
              )

# 軸のラベル
ax.set_xlabel('$X$', fontsize=15)
ax.set_ylabel('Frequency', fontsize=15)
ax.set_xlim(-0.5, 9); ax.set_ylim(0, 0.3)
ax.set_xticks(np.arange(0, 10, 1));
../_images/29ac045a2a901c6f7132c73c0ca84a3782f5bb90f414ceabaf61f639846441ba.png

5.4.4. 2次元ヒストグラム(ヒートマップ)#

データ分析では,2つの変数間の相関を見たり,2次元データの分布を可視化する場面がよくあり,このような場合にもヒストグラムが活躍する. 例えば,サッカーの試合においてフィールド上の各位置のシュート頻度を可視化したい場合, \((x, y)\) という2次元の座標データに対してシュート頻度(度数)を対応付ければ良い. 2次元ヒストグラムを可視化する方法の1つとして,度数を色の濃淡に対応させたヒートマップがある.

Matplotlibでヒートマップを可視化するには,ax.hist2dメソッドを用いる:

ax.hist2d(x_data, y_data, bins, option)
  • bins引数には \(x\) 方向と \(y\) 方向の階級数,または階級の左端の値をリストで指定する.

    • bins=10とした場合には\(x,\ y\)方向共に10個のbinに分割する.

    • bins=[10, 20]とした場合には \(x\) 方向を10個,\(y\) 方向を20個のbinに分割する.

オプション

内容

指定の仕方(例)

range

ヒートマップを求めるデータの範囲

[[x_min, x_max], [y_min, y_max]]

density

度数の規格化

True/False

cmin

表示するbinの度数の最小値

数値

cmax

表示するbinの度数の最大値

数値

# データの作成
X = np.random.normal(loc=0, scale=2, size=100000)
Y = np.random.normal(loc=0, scale=1, size=100000)
# 散布図
fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.plot(X, Y, '.', ms=0.1, alpha=0.3);
../_images/6ce161143540daeca5125686af98b632e03262122bf9ed154eb6205cd1728cfa.png
# ヒートマップ
fig, ax = plt.subplots()
ax.set_aspect('equal')
ret = ax.hist2d(X, Y, 
                bins=[100, 50],  # 100x50のbinに分割する
                range=[[-10, 10], [-5, 5]],  # 描画に使用するデータの範囲
                density=0,  # 度数の規格化
                cmin=1,     # 度数が1以上のbinだけ表示
                cmax=1000   # 度数が1000以下のbinだけ表示
                )  
../_images/fc64b993bb33ca62e4c34f984b9bbfac8673c0990011fdcd70a0880dd3e5f0bd.png

ヒートマップの装飾とカラーバーの追加

ヒートマップの色は各階級の度数に対応している. この色はカラーマップと呼ばれ,cmap='カラーマップの名前'のように指定できる. 主要なカラーマップには'jet'(デフォルト),'rainbow','gray','autumn'などがある. その他のカラーマップはここを参照のこと.

カラーマップと度数の対応はカラーバーとして可視化できる. ヒートマップにカラーバーを追加するにはFigureオブジェクトのfig.colorbarメソッドを用いる:

ret = ax.hist2d(X, Y, bins=[bx, by], option)
fig.colorbar(ret[3], option)

ここで,colorbarメソッドの第1引数にはhist2dメソッドの戻り値の第3成分を指定する. また,カラーバーの位置や大きさを調整するには,以下のオプションを使用する.

オプション

内容

指定の仕方(例)

orientation

カラーバーの向き

'vertical' / 'horizontal'

shrink

カラーバーの拡大率

数値

aspect

カラーバーの縦横比

数値

pad

カラーバーの位置

数値

# データの生成
X = np.random.normal(loc=0, scale=2, size=100000)
Y = np.random.normal(loc=0, scale=1, size=100000)

# ヒートマップの描画
fig, ax = plt.subplots()
ax.set_aspect('equal')
ret = ax.hist2d(X, Y, 
                bins=[100, 50], 
                range=[[-10, 10], [-5, 5]],
                cmap='jet', cmin=1)

# カラーバーを追加
fig.colorbar(ret[3], 
             orientation='vertical', # カラーバーの方向
             shrink=0.4, # カラーバーの拡大率
             aspect=10,  # カラーバーの縦横比
             pad=0.05    # カラーバーと図の間隔
             );
../_images/d4e030d1062661f2c3d6c3fc567b2e009edd576901825a586a0e38eb6ec57f0c.png

5.5. 章末問題#

次のcsvファイルをダウンロードし,カレントディレクトリに移動せよ:player_all.csv
このファイルには,2017年度にヨーロッパリーグ(イングランド,フランス,ドイツ,イタリア,スペイン)に所属していた選手のデータが保存されている.
※ 本データはPappalardoデータセットを加工したものである(詳細はイベントデータの解析).

df = pd.read_csv('./player_all.csv', header=0, index_col='player_id', na_values=0)
df
name team_id ... birthday league
player_id
3319 M_Özil 1609 ... 1988/10/15 England
3560 Nach_Monreal 1609 ... 1986/02/26 England
7855 L_Koscielny 1609 ... 1985/09/10 England
7870 A_Ramsey 1609 ... 1990/12/26 England
7882 P_Čech 1609 ... 1982/05/20 England
... ... ... ... ... ...
266885 M_Olunga 756 ... 1994/03/26 Spain
282448 Alei_García 756 ... 1997/06/28 Spain
366374 K_Soni 756 ... 1998/04/17 Spain
443324 Dougla_Luiz 756 ... 1998/05/09 Spain
508686 M_Lizak 756 ... 1996/07/15 Spain

2439 rows × 10 columns

問題A:体重の箱ひげ図

  • Englandリーグに所属する選手の体重のデータから欠損値を除外したデータは以下で取得できる.

    data1 = df.loc[df['league']=='England', 'weight'].dropna()
    
  • 全てのリーグに対して同様のデータを求め,以下のようなリストを作成せよ

    D = [data1, data2, ...]
    
# 解答欄
  • リストDを用いて,体重の箱ひげ図をリーグ別に作成せよ.ただし,横軸の目盛りをリーグ名とせよ.

# 解答欄

問題B:身長のヒストグラム

  • Englandリーグに所属する選手の身長のヒストグラムを作成せよ.

  • 作成したヒストグラムに,正規分布の確率密度関数を重ね書きせよ.ただし,平均値と標準偏差はデータから求めよ.

  • グラフを見やすく装飾せよ.

# 解答欄

問題C:身長と体重の相関

  • Englandリーグに所属する選手の身長を横軸,体重を縦軸に取ったヒートマップを作成せよ.

  • 身長と体重の相関係数を計算せよ.

# 解答欄