今回はNumPyのヒストグラムを作る関数であるhistogram関数について解説します。

matplotlibを使えば、直接ヒストグラムのグラフを作ることが可能ですが、値だけ知りたいというだけのときは、この関数が有効でしょう。もちろん、この関数で作成した配列をつかってmatplotlibで可視化することもできます。

まずは、APIドキュメントを確認してみましょう。

numpy.histogram(a, bins=10, range=None, normed=False, weights=None, density=None)

params:

パラメータ名 概要
a array_like
配列に相当するもの
ここで指定された配列の要素を元にヒストグラムを作成します。計算するために配列は1次元化されます。
bins intもしくは
スカラーのシーケンス
または文字列(string)
(省略可能)初期値10
intのときは、階級の数を指定します。ここがスカラーのシーケンスのときは、ビン(bins)の境界を決めることができます。文字列(string)のときはどの数式を用いてビンの幅を決めるか指定します。
range (float, float) (省略可能)初期値None
ビンの範囲を定めます。何も指定がないときは(a.min(), a.max())と、aの値の範囲となっています。
normed bool値 (省略可能)初期値False
非推奨の引数でver2.0以降はなくなるとされています。総面積が1となるように標準化するかどうかを指定します。この引数は使わず、densityを用いて指定しましょう。
weights array_like (省略可能)初期値None
カウントする際の重み(weights)を指定します。
density bool値 (省略可能)初期値None
Falseなら、各々のビンにおけるデータの個数が返されます。Trueなら、総面積が1となるよう標準化された度数が返されます。

returns:

度数の一覧の配列と、ビンの境界の配列のタプルが返されます。

引数として、binsでビンの境界などを指定し、rangeでビンの範囲を指定します。normedは公式サイトで非推奨の引数となっているため、今回は使わないことにします。weightsで各要素の重みを設定します。densityで標準化するかどうかを指定します。

binsの中には、文字列(string)で指定できるものがあり、それらは定められた計算方法を元にヒストグラムの算出を行います。しかしながら、このように指定している使用例はほとんど存在しないため、今回は説明を省略します。

まずは、基本的な使い方をみていきます。何も引数を指定せずに、とりあえずヒストグラムを作ってみます。

In [1]: import numpy as np

In [2]: a = np.random.randn(1000) # 標準正規分布に従った乱数を1000個生成。

In [3]: np.histogram(a) # 特に他の値を指定することなくヒストグラムを求めて見る。
Out[3]:
(array([ 24,  54, 119, 173, 225, 191, 121,  75,  13,   5]),
 array([-2.47057445, -1.92938389, -1.38819334, -0.84700278, -0.30581223,
         0.23537833,  0.77656888,  1.31775944,  1.85895   ,  2.40014055,
         2.94133111]))

In [4]: hist, bins = np.histogram(a) # こうすればヒストグラムをビンの境界の値を2つの変数に格納できる。  

In [5]: hist
Out[5]: array([ 24,  54, 119, 173, 225, 191, 121,  75,  13,   5])

In [6]: bins
Out[6]:
array([-2.47057445, -1.92938389, -1.38819334, -0.84700278, -0.30581223,
        0.23537833,  0.77656888,  1.31775944,  1.85895   ,  2.40014055,
        2.94133111])

rangeを変更してみます。これでビンの範囲を定めることができます。

In [21]: c = np.random.randint(10, size=30) # 0~9までの30個の乱数を生成。

In [22]: c
Out[22]:
array([6, 0, 2, 0, 6, 8, 9, 2, 3, 3, 0, 1, 1, 2, 7, 0, 7, 0, 1, 4, 0, 0, 4,
       2, 1, 1, 5, 5, 1, 8])

In [23]: np.histogram(c, range=(0,10))
Out[23]:
(array([7, 6, 4, 2, 2, 2, 2, 2, 2, 1]),
 array([  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.]))

In [24]: np.histogram(c) # 特に指定しないと範囲が変わる
Out[24]:
(array([7, 6, 4, 2, 2, 2, 2, 2, 2, 1]),
 array([ 0. ,  0.9,  1.8,  2.7,  3.6,  4.5,  5.4,  6.3,  7.2,  8.1,  9. ]))

In [25]: d = np.random.randn(40) # 次に標準正規分布に従った乱数を40個生成する。

In [26]: d
Out[26]:
array([-0.57536219, -0.69347388,  0.1393614 ,  0.63429668,  0.43178155,
       -0.76017997,  0.10223518,  1.83218158, -1.27366201,  0.88055922,
       -2.97331459,  1.131765  , -0.18579783,  0.17271408,  0.47829996,
        0.51160982, -0.72621177, -0.51790255,  1.37074374,  1.63805734,
       -1.22328913, -1.17902035,  0.05507337, -1.6558962 ,  1.39377438,
       -2.28915969, -0.10242263, -0.183241  , -2.28061513, -1.42468523,
        0.95696397, -0.47909867,  1.22995313,  0.17439689,  0.53453725,
       -0.32206571, -1.80340222, -1.37132107, -1.35783557, -0.36235529])

In [27]: np.histogram(d, range=(-3, 3)) # 値を見た感じ、-3~3の間におさまっていそうなのでこれを範囲として設定する。
Out[27]:
(array([1, 3, 6, 4, 8, 9, 4, 4, 1, 0]),
 array([-3. , -2.4, -1.8, -1.2, -0.6,  0. ,  0.6,  1.2,  1.8,  2.4,  3. ]))

次に、binsの値を変更していきます。初期値は10で、rangeの値が特に変更されていなければ、指定された配列の要素の最大値と最小値との間を10等分した区間となります。

In [7]: np.histogram(a, bins=5) # ビンの数を減らしたいときはbinsに数値を指定すればよい。
Out[7]:
(array([ 78, 292, 416, 196,  18]),
 array([-2.47057445, -1.38819334, -0.30581223,  0.77656888,  1.85895   ,
         2.94133111]))

In [8]: np.histogram(a, bins= np.arange(-3, 3) ) # このように境界を直接指定できる。
Out[8]: (array([ 21, 137, 335, 347, 148]), array([-3, -2, -1,  0,  1,  2]))

In [9]: np.histogram(a, bins=np.linspace(-3, 3, 20)) # linspaceで生成することもよくある。
Out[9]:
(array([  0,   4,  13,  27,  27,  62,  84,  97, 123, 121, 122, 111,  72,
         67,  38,  22,   5,   4,   1]),
 array([-3.        , -2.68421053, -2.36842105, -2.05263158, -1.73684211,
        -1.42105263, -1.10526316, -0.78947368, -0.47368421, -0.15789474,
         0.15789474,  0.47368421,  0.78947368,  1.10526316,  1.42105263,
         1.73684211,  2.05263158,  2.36842105,  2.68421053,  3.        ]))

次に、weightsを指定してみます。

In [10]: b = np.random.randint(-3, 4, size=20)  # ランダムな整数を20個生成。

In [11]: b
Out[11]:
array([ 2,  1, -1, -3, -3, -3,  1,  1,  1, -3, -3,  3,  3,  3,  1, -3,  1,
        0, -3,  3])

In [12]: weights = np.tile(np.array([1,0]),10)

In [13]: weights
Out[13]: array([1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0])


In [16]: np.histogram(b, bins = 6,weights=weights) # 重みを設定してヒストグラムを求めて見る
Out[16]: (array([3, 0, 1, 0, 4, 2]), array([-3., -2., -1.,  0.,  1.,  2.,  3.]))

次は標準化を行ってみましょう。これはdensityで指定することができます。本来はnormedがその役目を負っているはずですが、非推奨のため、densityで代用します。

In [17]: b # 先ほどと同じbの配列を用いる
Out[17]:
array([ 2,  1, -1, -3, -3, -3,  1,  1,  1, -3, -3,  3,  3,  3,  1, -3,  1,
        0, -3,  3])

In [18]: np.histogram(b, bins=6, density = False) # まずはFalseで見て見る
Out[18]: (array([7, 0, 1, 1, 6, 5]), array([-3., -2., -1.,  0.,  1.,  2.,  3.]))


In [20]: np.histogram(b, bins=6, density = True) # まずはTrueだと標準化されて値が1/20される(度数の合計が20で、ビンの幅がそれぞれ1なので)
(array([ 0.35,  0.  ,  0.05,  0.05,  0.3 ,  0.25]),
 array([-3., -2., -1.,  0.,  1.,  2.,  3.]))