棒グラフ、ドットプロット、円グラフ
棒グラフ、ドットプロット、円グラフ、整列棒グラフの描画スクリプト例を作成してみた。それぞれのタイプのグラフに関するSpiegelhalter (2019)の考え方の簡単な解説も付けておいた。
Pythonスクリプトの作成においては、Spiegelhalter(2019), p. xviに記載されているウェブサイトからダウンロードしたファイルを参考・利用した。
Spiegelhalter(2019), p. xviに記載されているウェブサイトからダウンロードしたファイルを参考にして、リスト1に示すPythonスクリプトを作成した。リスト1のスクリプトを実行すると図1に示すグラフが描画される。
図1
データファイル01-1-child-heart-survival-x.csvは、ダウンロードしたものである。それぞれの病院における子供の心臓手術における30日生存確率の棒グラフである。グラフのベースラインは86%に設定されている。この値は、20年前(Spiegelhalterの執筆時点から?)におけるBristol病院の低い値に基づいてかなり任意に設定されたものであるとSpiegelhalter(2019)は説明しつつ、論理的かつ有意味なベースラインに基づくべきであるというAlberto Cairoの主張を紹介している。さらにSpiegelhalter(2019)は、Nate Silverの「number do not speak for themselves – we are responsible for giving them meaning」という考え方に触れて、プリゼンテーションの選択の重要性を説いている。
棒グラフは、棒の長さを表す帯の心理学的影響があるので、帯のないドットプロットがよいとSpiegelhalter(2019)は言っている。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# ダウンロードしたファイルの読み込み
d_csv =
pd.read_csv('01-1-child-heart-survival-x.csv')
Hospital = d_csv['Hospital']
Percent30days = d_csv['ThirtyDaySurvival']
my_cmap =
plt.get_cmap("turbo")
v_to_c = lambda y: (y - np.min(y)) /
(np.max(y) - np.min(y))
plt.xlim(85,100)
plt.barh(Hospital, Percent30days,
color=my_cmap(v_to_c(Percent30days)))
plt.xlabel('% surviving 30 days',
fontsize=12)
plt.tight_layout()
plt.show()
図1のグラフをドットプロットで描き直すスクリプトをリスト2に示す。
リスト2のスクリプトを実行すると図2のグラフが表示される。
図2
図1の棒グラフにおいて、帯を外し、帯の先端を小円で描いたものである。数値データとしては、図1も図2も同じものであるが、帯のあるなしで印象に違いがある。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# ダウンロードしたファイルの読み込み
d_csv =
pd.read_csv('01-1-child-heart-survival-x.csv')
Hospital = d_csv['Hospital']
Percent30days = d_csv['ThirtyDaySurvival']
my_cmap =
plt.get_cmap("turbo")
v_to_c = lambda y: (y - np.min(y)) /
(np.max(y) - np.min(y))
#
描画範囲の設定
plt.xlim(85,100)
y_coord =
np.arange(len(Hospital))
# 病院名用数値ラベル
plt.scatter(Percent30days, y_coord,
s=120, color=my_cmap(v_to_c(Percent30days)))
plt.xlabel('% surviving 30 days',
fontsize=12)
plt.yticks(y_coord, Hospital)
plt.tight_layout()
plt.show()
Spiegelhalter(2019)のFigure 1.2には、2012―15に行われた小児心臓手術の病院別手術数の3D円グラフが表示されている。Spiegelhalter(201)は、3D円グラフは、受ける比率の印象が3Dによる歪みがあるのでよくないと説明している。リスト3では、2D円グラフを描いている。リスト3のスクリプトを実行すると、図3のグラフが表示される。
図3
データファイル01-2-child-heart-pie-chart-x.xlsxは、Spiegelhalter(2019), p. xviに記載されているウェブサイトからダウンロードしたものである。
import pandas as pd
import matplotlib.pyplot as plt
#
# ダウンロードしたExcelファイルの読み込み
#
with
pd.ExcelFile('01-2-child-heart-pie-chart-x.xlsx') as f_xlsx:
data =
pd.read_excel(f_xlsx);
Hospital = data.values.T[0][:-1]
PercentOps = data.values.T[1][:-1]
plt.title('Percentage of all
operations in\n' +
'2012-15 that are carried out in\n' +
'each hospital')
plt.pie(PercentOps, labels=Hospital,
autopct='%.1f%%')
plt.tight_layout()
plt.show()
棒グラフにおいて、帯を長さの順に並べると違いが強調される。リスト4は、2012―15に行われた小児心臓手術の病院別手術数の比率を比率の値の大きさの順に並べて棒グラフを描くものである。リスト4のスクリプトを実行すると、図4のグラフが表示される。
図4
病院間で違いがあることが良く分かるが、Spiegelhalter(2019)は、整列された棒グラフは違いが強調され過ぎると注意している。
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# ダウンロードしたファイルの読み込み
d_csv =
pd.read_csv('01-1-child-heart-survival-x.csv')
Hospital = d_csv['Hospital']
Operations = d_csv['Operations']
PercentOpe = Operations / np.sum(Operations)
* 100.0 # パーセント値
my_cmap =
plt.get_cmap("turbo")
v_to_c = lambda y: (y - np.min(y)) /
(np.max(y) - np.min(y))
#
# PercentOpeの値による並べ換え
#
idxsort = np.argsort(-PercentOpe)
PercentOpe = PercentOpe[idxsort]
Hospital = Hospital[idxsort]
plt.barh(Hospital, PercentOpe,
color=my_cmap(v_to_c(PercentOpe)))
plt.xlabel('Percentage of all
operations in 2012-15' +
'\nthat are carried out in each hospital', fontsize=12)
plt.tight_layout()
plt.show()
岡本安晴(2019) いまさら聞けないPythonでデータ分析.丸善出版
Spiegelhalter, D. (2019). The art of statistics: Learning from data. Pelican