今回は、分散を求める関数であるnp.var()
関数について解説します。まずは簡単な分散の復習から入りましょう。
分散
分散というのは一般的にデータのばらつき度合いを示すために使われる指標です。平均との偏差の2乗を平均したものが分散になります。式で表すと以下のようになります。
求める分散の値をとすると、
ここではの平均値を表しています。このの平方根をとったものが標準偏差です。 標準偏差が使われるのは、もととなるデータにおける単位を揃えるためです。分散のままだと単位はもとのデータの単位をそれぞれ2乗したものになってしまいます。
式を見てもらえばわかるように、平均からデータがどれくらい離れているのか、その平均をとることによって分散という指標はできています。 あくまで散らばり具合の基準点は平均となります。
np.var関数
では実際に関数の使い方を見ていきましょう。
APIドキュメント
まずはAPIドキュメントをみます。この関数のAPIドキュメントは以下の通りです。
**numpy.var(a, axis=None, dtype=None, out=None, ddof=0, keepdims=
params:
パラメータ名 | 型 | 概要 |
---|---|---|
a |
配列に相当するもの | 分散を求めたい配列を指定します。ndarrayでなかった場合変換が試みられます。 |
axis |
Noneもしくはint もしくはintのタプル |
(省略可能)初期値None どの軸(axis)に沿って分散を計算するかを指定します。Noneの場合、すべてのデータを対象に分散を求めます。 |
dtype |
データ型 | (省略可能)初期値None 分散を計算する際に用いるデータ型を指定します。デフォルトでは入力された配列が整数型の場合 float32 が指定され、それ以外の場合、aで指定された配列のデータ型に従います。 |
out |
ndarray | (省略可能)初期値None 結果を格納する配列をここで指定します。 |
ddof |
int | (省略可能)初期値0 分散を計算する際、平均との偏差の2乗の和を N-ddof で割ります。初期値ではddof=0なのでデータ数であるN で割ることになります。 |
keepdims |
bool値 | (省略可能)初期値no value 計算の結果、次元を縮小できる場合でも縮小可能な軸をサイズ1として維持します。 |
where |
array_like of bool値 | (省略可能)標準偏差の計算に含める要素かどうかを指定します |
returns:
outに何も指定されていない場合、求めた分散を格納した配列が返されます。
指定されている場合は出力された配列への参照が返されます。
指定できる引数が数多くあります。最初に分散を求めたい配列を指定します。axis
で分散を計算する方向を指定します。axis
については以下の記事で詳しく解説しているので気になる方は見てみてください。
dtype
で計算する際に用いるデータ型を指定し、out
で結果を格納する配列を指定します。
ddof
で分散を求める際にddof=0
であれば、与えられたデータを集合全体と見てその分散を求める標本分散をddof=1
ならば一部のデータから全体のデータの分散を計算する不偏分散を求めます。
NumPyの軸(axis)と次元数(ndim)は何を意味するのか /features/numpy-axis.html
標本分散と不偏分散については以下のサイトで詳しく解説されているので参考にしてみてください。
分散を求める
では、実際に使っていきましょう。特に引数を指定せずにデータ全体の分散を求めてみます。
In [1]: import numpy as np
In [2]: a = np.array([10, 20, 12, 0, 3, 5])
In [3]: np.var(a) # 特に引数を指定しない場合は6つのデータから分散を求める。
Out[3]: 43.55555555555555
次にaxis
を指定してみます。
In [4]: b = np.random.randint(20, size=(3,4))
In [5]: b # bの中身を確認。
Out[5]:
array([[ 3, 13, 12, 1],
[10, 19, 1, 6],
[ 8, 13, 12, 18]])
In [6]: np.var(b) # 特にaxisを指定しないと全体の分散を求める。
Out[6]: 33.388888888888886
In [7]: np.var(b, axis=0) # 行方向の分散を求める
Out[7]: array([ 8.66666667, 8. , 26.88888889, 50.88888889])
In [8]: np.var(b, axis=1) # 列方向の分散を求める
Out[8]: array([ 28.1875, 43.5 , 12.6875])
In [10]: np.var(b, axis=(0,1)) # こうすると0,1番目の軸方向でやるとすべての範囲の分散を求める
Out[10]: 33.388888888888886
次にdtype
を指定します。
In [16]: c = np.random.randn(100).reshape(5,20) # 標準正規分布からランダムな数列を生成。
In [18]: c.dtype # データ型を確認
Out[18]: dtype('float64')
In [19]: c
Out[19]:
array([[ 0.35225642, 0.42735088, 0.22483062, -1.29718125, 0.19805096,
-0.52872563, -0.37953642, 1.35085875, 1.06166236, -1.14408896,
1.54089466, 0.5729667 , -1.55339662, -1.11796015, -0.30161906,
-0.04310339, -0.90791445, 1.33607073, -1.1710254 , 1.49489929],
[ 2.01375678, -0.64110448, 0.18106096, -0.03658098, -0.62123187,
-0.61729062, 0.19154253, 0.93459067, -1.67334457, -1.77243433,
1.17715007, -0.58395848, 0.64823962, -0.19429409, 0.40297725,
0.38401512, -0.55167875, -0.30052436, -0.86550869, -1.29361117],
[ 0.00993361, 0.48064153, 0.12597228, -0.13348795, 0.13881167,
-1.40062426, 0.33302593, -1.07486468, 0.22216967, -0.79206793,
-0.64137661, -1.80691328, -1.18824 , -0.23372683, -0.35116358,
0.95200835, 0.3781709 , -1.23003955, -1.35842974, -1.05603139],
[-1.48968822, -1.26374257, 0.80641034, 0.05188685, -0.42511282,
0.12333293, 3.26526552, -2.05103589, 0.8892263 , -1.83975271,
1.09835528, 0.86211006, -1.15216875, -0.57875082, -0.63924306,
-0.40284799, -0.16096745, -0.59009197, -0.61755593, -0.86973981],
[-0.47688695, 0.62437855, -0.32973941, 0.0707855 , 1.18317729,
0.37800033, -1.30444915, 2.28224717, 0.10517787, 0.1081565 ,
0.73538965, 1.28810643, -1.70036478, 1.60113382, -1.18890108,
-1.61474179, 0.71776759, -1.95725267, -0.15671136, -0.91014567]])
In [20]: np.var(c, dtype='float32') # dtypeを指定する。
Out[20]: 1.043533
In [22]: np.var(c, dtype='float64')
Out[22]: 1.0435329101767985
ddofを指定する
次にddof
を変更してみます。先程の標準正規分布から生成した配列のサンプルデータ数を少なくして分散がddof=0,ddof=1
のどちらの場合のほうが、分散がより1に近づくか見てみましょう。
In [23]: d = np.random.randn(10) # 10個のサンプルデータから計算してみる。
In [24]: d
Out[24]:
array([-1.87744275, 1.02445975, 0.02985718, -0.96668578, 1.45083393,
-0.19564106, -0.72043885, -0.45597266, -1.49547549, -1.33429341])
In [25]: np.var(d, ddof=0) # まずはデフォルトの値であるddof=0から。(標本分散)
Out[25]: 1.0334719835739459
In [26]: np.var(d, ddof=1) # 次は不偏分散を求める。
Out[26]: 1.1483022039710509
In [27]: e = np.random.randn(5) # もっとサンプル数を減らしてみる
In [28]: e
Out[28]: array([-1.76749733, -2.19574813, -0.54184825, -0.80253071, -0.65802786])
In [29]: np.var(e)
Out[29]: 0.43964219645143265
In [30]: np.var(e, ddof=1) # 1により近づく。
Out[30]: 0.54955274556429079
サンプル数を少なくするほど母集団の分散を計算できていることがわかります。
配列の次元数を保存する
最後はkeepdims
です。keepdimをTrueにすることでブロードキャストを適用します。例えば計算した分散の値でもとのデータを割りたいときにはkeepdims=True
にすると安全です。
In [31]: f = np.random.randint(20, size=(2,5,10)) # 3次元のランダム配列
In [32]: f
Out[32]:
array([[[13, 7, 7, 13, 19, 17, 1, 17, 8, 12],
[19, 5, 5, 5, 14, 11, 3, 5, 0, 12],
[ 2, 17, 14, 4, 6, 19, 14, 15, 12, 14],
[16, 6, 12, 2, 12, 11, 9, 18, 0, 13],
[ 0, 13, 10, 10, 6, 2, 4, 11, 18, 6]],
[[ 9, 5, 7, 8, 18, 4, 14, 7, 3, 11],
[ 5, 10, 11, 3, 10, 19, 12, 5, 18, 0],
[17, 3, 18, 0, 14, 12, 1, 16, 4, 9],
[ 6, 0, 12, 11, 9, 2, 1, 19, 14, 7],
[ 1, 5, 12, 9, 11, 19, 14, 12, 0, 7]]])
In [33]: f_var = np.var(f, axis=1) # それぞれの列方向の分散を求める
In [34]: f/f_var # これだとブロードキャストがうまく適用されない
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-34-0ad664488579> in <module>()
----> 1 f/f_var # これだとブロードキャストがうまく適用されない
ValueError: operands could not be broadcast together with shapes (2,5,10) (2,10)
In [35]: f_var.shape # 形状を確認してみる。
Out[35]: (2, 10)
In [36]: f_var = np.var(f, axis=1, keepdims=True) # それぞれの列方向の分散を求める
In [37]: f/f_var # keepdimsをTrueにするとうまく計算できる。
Out[37]:
array([[[ 0.22413793, 0.32649254, 0.65789474, 0.78502415, 0.7711039 ,
0.48295455, 0.04512635, 0.7535461 , 0.16447368, 1.53061224],
[ 0.32758621, 0.23320896, 0.46992481, 0.30193237, 0.56818182,
0.3125 , 0.13537906, 0.22163121, 0. , 1.53061224],
[ 0.03448276, 0.79291045, 1.31578947, 0.24154589, 0.24350649,
0.53977273, 0.63176895, 0.66489362, 0.24671053, 1.78571429],
[ 0.27586207, 0.27985075, 1.12781955, 0.12077295, 0.48701299,
0.3125 , 0.40613718, 0.79787234, 0. , 1.65816327],
[ 0. , 0.60634328, 0.93984962, 0.60386473, 0.24350649,
0.05681818, 0.18050542, 0.48758865, 0.37006579, 0.76530612]],
[[ 0.31424581, 0.46992481, 0.56451613, 0.48309179, 1.69172932,
0.07727975, 0.37796976, 0.25216138, 0.06229236, 0.7994186 ],
[ 0.17458101, 0.93984962, 0.88709677, 0.18115942, 0.93984962,
0.36707883, 0.32397408, 0.18011527, 0.37375415, 0. ],
[ 0.59357542, 0.28195489, 1.4516129 , 0. , 1.31578947,
0.23183926, 0.02699784, 0.57636888, 0.08305648, 0.65406977],
[ 0.20949721, 0. , 0.96774194, 0.66425121, 0.84586466,
0.03863988, 0.02699784, 0.68443804, 0.29069767, 0.50872093],
[ 0.0349162 , 0.46992481, 0.96774194, 0.54347826, 1.03383459,
0.36707883, 0.37796976, 0.43227666, 0. , 0.50872093]]])