よちよちpython

独習 python/Qpython/Pydroid3/termux

numpyとmatplotlibで簡単ヒストグラム作図

2020年の年が明けました。
おめでとうございます。

今年最初の投稿は、ヒストグラムを図示することをやってみます。



実行環境


Androidスマホ
termux
Python3.8
Jupyter Notebook



ヒストグラムとは?


ヒストグラム(英語: histogram[1])とは、縦軸に度数、横軸に階級をとった統計グラフの一種で、データの分布状況を視覚的に認識するために主に統計学や数学、画像処理等で用いられる。柱図表[1]、度数分布図、柱状グラフともいう。(Wikipedia)

何のこっちゃ分かりませんが、データを幾つかの区分にわけ、それらの区分にデータが何個ずつあるかを棒グラフで表したもの。
横軸に区分したデータの値、縦軸にデータの頻出度を表します。

見た方が早いので、以下の簡単な例で実際に示します。



クラスのテストデータをこしらえる


満点が100点のテストのデータが1クラス分ある例を考えます。

  • クラスの人数は30人とします。
  • 点数は0~100点の取り得る値。

漢字のテストなど何か1科目の30人分のデータがあるとします。 が、そのようなデータが手元にないので、先にnumpyでランダムな整数を発生させて作ることにします。

まずはnumpyのインポート。
インストールが未だならpip install numpy等で行ってから。

import numpy as np

では次に、30人分のデータの生成。

np.random.randint(最小値, 最大値, 個数)を使うと、最小値~最大値の範囲でランダムに選ばれた整数が指定個数だけ並んだnumpy配列を作ることができます。

ランダムな整数n、最小値min、最大値maxとすると
min <= n < max
の範囲です。最大値に指定した数値未満。その数値を含みませんので注意。

tensuu = np.random.randint(0,101,30)
tensuu
array([ 54,  48,  92,  71,   2,  52,  61,  85,   3,  42,  50,  14,   3,
        13,  77,  85,  11,  24,  25,  58,  97,   6,  26,  38,  26,  41,
        86, 100,  21,  94])

0から100点まででランダムに選んだ30個、30人分のデータが出来ました。一応データの形を出しておきます。

tensuu.shape
(30,)

30個の一次元配列。



ヒストグラムの作図


matplotlibを使ってグラフを描きます。インポート。

import matplotlib.pyplot as plt

plt.hist(データ, bins='階級の分割数')を使うと、この場合0~100点までを何階級かに分割され、それぞれの階級に何人入っているかが棒グラフで図示されます。このようなグラフをヒストグラムといいます。

bins=10にして、10点ずつの階級に分けてやってみます。

plt.hist(tensuu,bins=10)
plt.savefig("tensuu.png") #グラフの保存
plt.show()

f:id:chayarokurokuro:20200101023533p:plain

bins=10にしたので10点ずつに区切った棒グラフが合計10本できています。
縦軸は、その区分にデータが何個あるかを示しています。合計するとちゃんと30個になっています。



試しに50点で2分割したグラフと、5点ずつで区分したグラフを描いてみます。

bins=2

plt.hist(tensuu,2)
plt.savefig("tensuu_2.png")
plt.show()

f:id:chayarokurokuro:20200101023606p:plain

bins=20

plt.hist(tensuu,20)
plt.savefig("tensuu_3.png")
plt.show()

f:id:chayarokurokuro:20200101023640p:plain

10000個のデータを10階級に分けたらどんなグラフになるでしょうか?

x = np.random.randint(0,101,10000)
plt.hist(x,bins=10)
plt.savefig("hist_10000.png")
plt.show()

f:id:chayarokurokuro:20200101023725p:plain

randint()は一様分布な疑似乱数を発生させるらしいので、上のように長方形の形をしたグラフになります。
バランスよくバラけているってことです。



しかし、実際のデータなら、難しいテストだと低得点に片寄り、簡単なテストなら高得点に偏るといったことになる筈なので、上のような長方形のグラフにはならないと思われます。

hist()の引数について


データの形状


上の例でhist()の引数で渡したデータは一次元のnumpy配列でした。
多次元のデータではどうなるかを示しておきます。

2列のデータ

# 2列に変換
x = x.reshape(-1,2)
x
array([[63, 79],
       [37, 31],
       [98, 90],
       ...,
       [58, 79],
       [85, 87],
       [95, 96]])

配列の形状を確認します。

x.shape
(5000, 2)

10000個の一次元データが、5000行2列のデータに変換されてました。



グラフ化します。

plt.hist(x,bins=10)
plt.savefig("hist_2_10000.png")
plt.show()

f:id:chayarokurokuro:20200101023821p:plain

色ちがいのグラフが出ました。
何で色が別かれてあるかが分かりやすいように、配列の2列目の値を全て1に変えてやってみます。

x[:,1] = 1
x
array([[63,  1],
       [37,  1],
       [98,  1],
       ...,
       [58,  1],
       [85,  1],
       [95,  1]])
plt.hist(x,bins=10)
plt.savefig("hist_3_10000.png")
plt.show()

f:id:chayarokurokuro:20200101023918p:plain

青色のグラフは500個ぐらいの頻度で各階級に平均的に散らばっていますが、橙色のグラフは1本の棒グラフで5000個の度数を占めています。
列ごとに別けてグラフ化してくれているのですね。5教科のデータを一括でヒストグラムに表す時などに使えそうです。



5列のデータ

# データを5列で生成
y = np.random.randint(0,100,10000)
y_c = y.reshape(-1,5)
y_c
array([[18, 58, 27, 90, 96],
       [22, 98, 12, 83, 61],
       [81, 60,  7, 41, 34],
       ...,
       [15, 56, 14, 24, 51],
       [34, 88, 58, 60, 19],
       [86, 93, 32, 41, 87]])
plt.hist(y_c,bins=10)
plt.savefig("hist_4.png")
plt.show()

f:id:chayarokurokuro:20200101024016p:plain

データはリストでも出来ます。

# numpy配列を生成
z = np.random.randint(0,100,1000)

# numpy配列をリストに変換
z_list = z.tolist()
plt.hist(z_list,bins=10)
plt.savefig("hist_5_list.png")
plt.show()

f:id:chayarokurokuro:20200101024110p:plain


追記
上の2つのデータのrandint()の2番目の引数が100になってますね。間違えました。これだと0~99点の範囲の乱数になります。


bins 階級の数


データの取り得る値を指定の数値で階級に区分します。
指定しなければデフォルトでbins=10になっているようです。

その他のパラメータ


今回はデータとbinsしか使っていませんが、その他にいくつかあります。


パラメータ 説明
range X軸のデータ表示範囲 int
normed 縮尺(1で最大値1の出現確率に、0でデータ数) boolean
histtype barは通常、barstackedは積み上げ、stepは外枠だけの階段状、stepfilledは階段を塗りつぶし str
color 色(blue,green,red,cyan,magenta,yellow,black,whiteが使える) str
alpha 透過率 float
label データラベル str


参照
matplotlibのヒストグラム用パラメータ抜粋 - Qiita

matplotlib公式ドキュメント
pyplot — Matplotlib 2.0.2 documentation

さいごに


ヒストグラムはデータをいくつかの区分で階級別けして、その階級に属するデータの個数がいくつあるのかを調べる時に使えることが分かりました。
24時間の短時間降水量データを10年分ぐらい集めてヒストグラムを作り、集中豪雨の頻度が年を追うごとに増えているようなことがわかれば同時に水害の発生確率が上がっている事もわかるかと思います。
その他にも交通渋滞の曜日や時間ごとの頻度だとか商品の売り上げの頻度を分析する時とか、これを使えばいろいろ見えて来そうです。

今回は以上です。
よいお年を!!