慶應通信の統計学レポートを作るときに必死こいて調べたmatplotlibを使ったグラフ作成の覚書
なんでわざわざmatplotlibでグラフ描くの?と、問われれば「なんかカッコイイと思ったから」以上の答えが用意できていない。そしてさらに、僕はPythonをマスターしたエンジニアでもなければなんでもない。だから内容はおそらくPythonエンジニアの方々からしたら鼻くそみたいなレベルのものなのであろう。それにまだまだレポートが全部終わった訳ではないので、この記事の内容で全部グラフ描けるぜ!という次元には至らない。でもこのまま統計学で作成するレポートでmatplotlibを使った軌跡は自身の備忘を目的としてここに残しておこうかと思う。大学のレポートとかをPythonが得意な訳でもなんでもないけどmatplotlibで描いてみようとか考えたすげぇ特殊なケースの人が居るかもしれな…居ないか。でも、でもね!階級幅が違うヒストグラムを描くのであれば絶対matplotlibのが楽だから!絶対!w
スポンサーリンク
普通のヒストグラムの書き方
matplotlibでヒストグラムを描くのはそう難しくない。あるデータの集合A_histがリストで存在するとすると、
# 必要なものをインポート import matplotlib.pyplot as plt # グラフ描画のおまじない fig = plt.figure() ax = fig.add_subplot(1,1,1) # A_histのリスト内容をヒストグラムで描画、線は黒 ax.hist(A_hist,ec='black')
これだけ。でもこの描画方法だと、
- 区間が自動で切られてしまうので、階級図が与えられている時に使えない
- 実数でしか描けないので、正規化(%表示)するのにまた違うリスト作らなきゃいかんやん
といったあたりが課題として挙げられる。なので、まずは正規化する方法に関して。
正規化したヒストグラム
正規化するのに別に違うデータを用意しなくても大丈夫。さっきのヒストグラムのコードにdensity=True
って追記するだけ。
追記前 ~ before ~
ax.hist(A_hist,ec='black')
追記後 ~ after ~
ax.hist(A_hist,ec='black',density=True)
これだけで、勝手に割合計算して正規化されたヒストグラムが完成する。あら便利(Excelも簡単に正規化出来るけどさ)
軸をパーセント表記にしたいんだよ!
前項までで正規化したヒストグラムは完成したが、実はひとつ足りない。縦軸の数値が小数点表記なのだよ。正規化したんだから、パーセント表記じゃなきゃダメでしょ!という訳でそちらの対応。対応方法は、ちょろっとコードを書き足すだけ。
# 必要なものを追加インポート import matplotlib # A_histのリスト内容をヒストグラムで描画、線は黒 ax.hist(A_hist,ec='black',density=True) # Y軸をパーセント表記に ax.yaxis.set_major_formatter( matplotlib.ticker.PercentFormatter(1.0) )
追加でimport matplotlib
を行ったのち、yaxis.set_major_formatter()
を使ってY軸をパーセント表記に変えている。多分このyaxis
をxaxis
にしたらX軸が変えれるのかな?変えたことないからわからんけどw
階級幅が違うヒストグラム
ただし、このヒストグラムでは階級幅が異なる階級表からヒストグラムを作ることがうまくできない。だってmatplotlibでヒストグラム作ると適当(いい意味でも悪い意味でも)な階級幅でいい感じに作ってくれちゃうから。なので、階級幅を自分で定義したヒストグラムを作るにはどうすれば良いのか。それは…
binsを指定してやれば良い
これだけ。だけどここに行き着くのに散々ネットの海を彷徨ったよ…。実際のコードはこちら。
# 階級幅をリストに格納する。 # 下のリストは、50-53,53-61,…,72-80という階級幅を表す edges = [50,53,61,64,65,69,72,80] # ヒストグラム描画コードにbinsを渡す ax.hist(A_hist,bins=edges,ec='black')
と、こうなる。普通のヒストグラム作成のときにもbinの数を指定する際にとか使ったよね。このパラメータ。
Excelのデータラベル的な文字を付ける
Excelでグラフを描くと、右クリック一発で「データラベルの作成」が選べて、グラフの上端にその数値が出たりなどなど、素敵な処理が簡単に出来る。ではmatplotlibでそれは出来るのか。答えは…
出来る。けどちょっと面倒くさい
となる。まぁ結局やることはplt.text
を使って直接文字を打ち込むだけなんだけど。ちなみにこのplt.text
は覚えておくと便利なのでちょっとだけ解説。
plt.text(x座標,y座標,'表示させたいテキスト')
これだけでグラフの任意の場所にテキストを表示させられる。だから本項の目的であるデータラベル的な文字列表示も、位置さえ分かれば自由自在ですよ。位置さえ分かれば…。という訳で、位置の特定に進む。
位置の特定は、ax.hist()
の戻り値を使うことで可能。ax.hist()
は3つの戻り値を返すので先ほどのコードをちょっと変えてやる。
n, bins, _ = ax.hist(A_hist,bins=edges,ec='black')
これはax.hist()
から貰える戻り値を3つの変数に格納している。最後の_
は使わないから「使わないぜこの変数!」という硬い意思が見え隠れする変数名にしておいた。で、n
は「n番目のbinはこの高さよ」というリストを返してくれて、bins
はbinsそれぞれの左側のx座標と右側のx座標をリストで返してくれる。だから、先に使ったedges
のリストで説明すると…。
edges = [50,53,61,64,65,69,72,80]
というリストで描いたヒストグラムにおけるbins
の戻り値リストは、
- 1番目の左側のx座標
- 2番目の左側のx座標(=1番目の右側のx座標)
- 3番目の左側のx座標(=2番目の右側のx座標)
- …
- n番目の左側のx座標(=n-1番目の右側のx座標)
- n番目の右側のx座標
というものになる。で、データラベル的なものはbins
の上、真ん中あたりにテキストを表示させたい訳なので、
n番目のbinsのデータラベルとしてテキストをプロットするx座標は、bins
のn-1番目とn番目の平均を取った数値
という結論に至る。んでy座標はそのままヒストグラムの高さのちょっと上なので、ヒストグラムのnのリストに格納されているY座標の数値にちょっと数値を足してやることにする。だから実際のコードは…
### グラフ描画しつつ、戻り値を取得 n, bins, _ = ax.hist(A_hist,bins=edges,ec='black',density=True) ### 前の行で取得したbinsを使って平均算出 xs = (bins[:-1] + bins[1:])/2 ### 繰り返し処理を使ってテキストを表示していく ### shareのリストは全体の何パーセントかの数値が格納されている ### 表示テキストはパーセント for x, y in zip(xs, n): plt.text( x, y + 0.005, '構成比\n {:.1%}'.format(share[z]), horizontalalignment='center' ) z = z + 1
最終的に出来上がったヒストグラムはこんな感じ。(レポートで使ったグラフなので、数値はボカしてあります…)何か疑問が発生する度にググってみては失敗して、ググってみては失敗して…を繰り返したので、いっそ手書きでヒストグラム作った方が楽だったんじゃいないのかという説すら自身で否定できなかったw
いつまでこの熱が続くかなぁ…Excelに逃げちゃいそうだなぁ…。
シナジーがあるとは思えないけどシリーズになりそうな慶應通信 × Pythonシリーズはこちら。
Pythonによるデータ分析入門 第2版 ―NumPy、pandasを使ったデータ処理
- 作者:Wes McKinney
- 発売日: 2018/07/26
- メディア: 単行本(ソフトカバー)