NumPyには配列の要素の平均を求める関数numpy.averagenumpy.meanの2つの関数があります。

今回の記事では、

  • averagemeanの違い
  • 各々の関数の使い方

について解説します。

averageとmeanの違い

まずはこれら2つの関数の違いについて解説します。

一番大きな違いは、average関数には重み付き(weighted)の平均を求められますが、mean関数にはそのような機能がないことです。すなわち、重み付き平均を求めたい場合にはaverageを使用します。

その他には、mean関数では平均を計算する際のデータ型をdtypeで指定することができますが、average関数では指定することができません。

以下の表に、average関数でできることとmean関数でできることの詳細をまとめました。

  np.average np.mean
重み付きの平均 ×
データ型を指定 ×
平均を計算する軸(axis)の方向を指定
軸(axis)の数を減らさない形で平均を返す ×

np.average

np.average関数から使い方を解説します。np.average関数のAPIドキュメントは以下の通りです。

**np.average(a, axis = None, weights = None, returned = False, keepdims=)**

params:

パラメータ名 概要
a array_like
(配列に相当するもの)
平均を求めたい配列を指定します。
axis intもしくは
intのタプル
(省略可能)初期値None
どの軸(axis)方向にそって平均を計算するかを指定します。デフォルトでは全ての要素についての平均を返します。
weights array_like (省略可能)初期値None
平均を求める際にそれぞれの要素につける重みを設定します。この割り当てられる値が大きいほどその要素の平均に対して及ぼす影響が大きくなります。
returned bool (省略可能)初期値”False”
値を返す際に、(平均, 重みの合計)といったタプルの形にするかどうかを指定します。
keepdims bool (省略可能)初期値no value。計算の結果、次元を縮小できる場合でも縮小可能な軸をサイズ1として維持します。

returns:

指定された方法で計算された平均の値が返されます。軸が指定されているときは配列の形で返され、returned=Trueのときは(平均, 重みの合計)の形で値が返されます。

この関数は第1引数に、平均を求めたい配列を、第2引数に平均を求める軸の方向を、第3引数に重みを、第4引数に値の返し方を、第5引数に出力配列の次元数を入力配列と同じに維持するかどうかを指定します。

基本的な使い方

それぞれの引数を見ながら使い方を見て見ましょう。まずは、平均を求めたい配列だけを指定する場合から見ていきましょう。

In [1]: import numpy as np

In [2]: a = np.array([33, 44, 54, 23, 25, 55, 32, 76]) # 適当な配列を1つ作る。

In [3]: np.average(a) # まずはaの平均を求めてみる。
Out[3]: 42.75

In [4]: a = a.reshape(2,4) # aのshapeを変更。

In [5]: a
Out[5]:
array([[33, 44, 54, 23],
       [25, 55, 32, 76]])

In [6]: np.average(a) # aの形状に関わらず、引数にaxisが指定されていなければ1つのスカラー量だけ返される。
Out[6]: 42.75

軸の指定

次に軸(axis)を指定してみます。

In [7]: np.average(a, axis = 0) # 軸(axis)を指定する。2次元配列でaxis =0のときは行方向の平均を求める。
Out[7]: array([ 29. ,  49.5,  43. ,  49.5])

In [8]: np.average(a, axis = 1) # axis = 1のときは列方向の平均を求める。
Out[8]: array([ 38.5,  47. ])


In [10]: b = np.random.rand(24).reshape(2,3,4) # 3次元の配列でも確かめておく。

In [11]: b
Out[11]:
array([[[ 0.11076868,  0.34832254,  0.36064024,  0.1229295 ],
        [ 0.54269798,  0.84373625,  0.70098021,  0.32525671],
        [ 0.11554616,  0.6299628 ,  0.75165631,  0.59971063]],

       [[ 0.28207248,  0.71686235,  0.81355244,  0.83476733],
        [ 0.92493115,  0.05083893,  0.96601166,  0.98868334],
        [ 0.41412407,  0.23077686,  0.71536231,  0.61265456]]])

In [12]: np.average(b, axis = 0) # 大きく2つに分かれた配列の2つの要素の平均をそれぞれ求める。  
Out[12]:
array([[ 0.19642058,  0.53259244,  0.58709634,  0.47884841],
       [ 0.73381456,  0.44728759,  0.83349594,  0.65697002],
       [ 0.26483511,  0.43036983,  0.73350931,  0.6061826 ]])

In [13]: np.average(b, axis = 1) # 行方向の平均をとる。
Out[13]:
array([[ 0.25633761,  0.60734053,  0.60442558,  0.34929895],
       [ 0.5403759 ,  0.33282605,  0.83164214,  0.81203508]])

In [14]: np.average(b, axis = 2) # 列方向の平均をとる。
Out[14]:
array([[ 0.23566524,  0.60316779,  0.52421897],
       [ 0.66181365,  0.73261627,  0.49322945]])

重みの指定

次に重み(weights)を設定します。

In [15]: a = a.flatten() # aを1次元配列に変形。

In [16]: w = np.array([0.1, 0.05, 0.2, 0.0, 0.0, 0.4, 0.2, 0.05]) # 重みを設定。

In [17]: np.average(a, weights = w) # 重みつきの平均を求める。
Out[17]: 48.5

In [18]: w2 = np.array([0.2, 0.8])

In [19]: a = a.reshape(2,4) # またaのshapeを変更する。

In [20]: np.average(a, axis = 0, weights = w2) # 指定した軸方向の要素数が一致しており、かつ重みの配列が1次元配列であるとき、ブロードキャストが適用される。
Out[20]: array([ 26.6,  52.8,  36.4,  65.4])

重みの合計を表示

最後に、returnedについて見ていきます。これは、値を返す際に重みの合計を表示するかどうかを指定できる引数です。
引数であるweightsに何も指定していないと、各要素の重みは1.0として重みの合計が計算されます。

In [21]: np.average(a, returned = "True") # 重みを設定しないと、各々の要素の重みが1.0に設定されるので、重みの合計は要素数と一致する。
Out[21]: (42.75, 8.0)

In [22]: a = a.flatten() # 1を1次元配列に変形。

In [23]: a
Out[23]: array([33, 44, 54, 23, 25, 55, 32, 76])

In [24]: w
Out[24]: array([ 0.1 ,  0.05,  0.2 ,  0.  ,  0.  ,  0.4 ,  0.2 ,  0.05])

In [25]: np.average(a, weights = w, returned = "True") # この状態で実行すれば、平均、重さの合計が表示される。
Out[25]: (48.5, 1.0)

np.mean

次に、np.mean関数について解説します。この関数は、np.average関数に比べると重み付きなどは出来ないので、純粋に要素の平均を求めるために使用します。

np.average関数に無い機能として一番大きいのは、平均を求める際に使うデータ型を指定できることです。

np.mean関数のAPIドキュメントは以下のようになっています。

**numpy.mean(a, axis = None, dtype = None, out = None, keepdims = , ..., where=)**

params:

パラメータ名 概要
a array_like
(arrayに相当するもの)
平均を求めたい配列を指定します。
axis intもしくは
intのタプル
(省略可能)初期値None
どの軸(axis)に沿って平均を求めるかを指定します。
dtype dtype (省略可能)初期値None
平均を求める際に使用するデータ型を指定します。
out ndarray (省略可能)初期値None
計算結果を格納するための配列を指定します。
keepdims bool
(TrueまたはFalse)
(省略可能)初期値”False”
返す配列の軸(axis)の数をそのままにする(その軸での要素数を1にする)かどうかを指定します。
where bool 各要素を平均値の計算に含める要素かどうかの配列を指定します

returns:

指定した配列の要素の平均、もしくは平均を要素とする配列が返されます。

1つ目の引数で平均を求めたい配列を指定します。次に、2つ目の引数axisでどの軸(axis)に沿って平均を求めていくかを決め、3つ目の引数dtypeで計算する際に用いるデータ型を指定します。4つ目の引数outで結果を格納する値を指定し、5つ目の引数keepdimsで結果の配列の軸(axis)の数をそのままにするかどうかを指定します。6つ目の引数whereで平均値の計算に含める要素を指定します。

やっている操作自体は純粋な要素の平均を求めているだけで、その結果をどう出力するかを引数で指定していくイメージです。

基本的な使い方

まずは、aだけを指定した例から見ていきましょう。

In [1]: import numpy as np

In [2]: a = np.random.randint(0, 10, 20) # 0~9までのランダムな整数を20個生成。

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

In [4]: np.mean(a) # 平均を求める。
Out[4]: 4.0999999999999996

In [5]: b = a.reshape(4,5) # aを4×5の二次元配列に変形したものをbに代入。

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

In [7]: np.mean(b) # shapeを変更しても結果は変わらない。
Out[7]: 4.0999999999999996

軸を指定する

次に、軸(axis)を指定していきます。

In [8]: np.mean(b, axis = 0) # 行方向、つまり列ごとの平均を求めていく。
Out[8]: array([ 3.25,  4.5 ,  4.  ,  4.  ,  4.75])

In [9]: np.mean(b, axis = 1) # 列方向、つまり行ごとの平均を求めていく。
Out[9]: array([ 2.2,  3.8,  5.2,  5.2])

In [10]: c = np.random.rand(24).reshape((2,3,4)) # 3次元配列でも試していく。

In [11]: c # 今度は0~1の範囲で乱数を24個生成。
Out[11]:
array([[[ 0.95979688,  0.08343238,  0.33695294,  0.78382111],
        [ 0.36685429,  0.86955043,  0.88227388,  0.79091495],
        [ 0.63368575,  0.5130265 ,  0.0619997 ,  0.6573761 ]],

       [[ 0.45284015,  0.08635302,  0.94612675,  0.33949862],
        [ 0.17685103,  0.26249988,  0.44127751,  0.3318031 ],
        [ 0.18581007,  0.66045853,  0.29541049,  0.33626342]]])

In [12]: np.mean(c, axis = 0) # 軸(axis)が3つある配列でのaxis = 0は2つに分かれた配列方向のもの。この場合、2つの配列の相当する要素における平均をそれぞれ求めていっている。
Out[12]:
array([[ 0.70631851,  0.0848927 ,  0.64153984,  0.56165986],
       [ 0.27185266,  0.56602515,  0.6617757 ,  0.56135903],
       [ 0.40974791,  0.58674251,  0.17870509,  0.49681976]])

In [13]: np.mean(c, axis = 1) # これが軸が2つある状態での行方向、つまり列ごとの平均を求めるもの。
Out[13]:
array([[ 0.65344564,  0.48866977,  0.42707551,  0.74403739],
       [ 0.27183375,  0.33643714,  0.56093825,  0.33585505]])

In [14]: np.mean(c, axis = 2) # これが軸が2つある状態での列方向、つまり行ごとの平均を求めるもの。  
Out[14]:
array([[ 0.54100083,  0.72739839,  0.46652201],
       [ 0.45620463,  0.30310788,  0.36948563]])

データ型の指定

次はdtypeを指定していきます。これによって計算の精度が変わってきます。

In [18]: d = np.random.rand(1000) # 乱数を1000個生成。

In [19]: d.dtype # dtypeを確認。
Out[19]: dtype('float64')

In [20]: np.mean(d) # まずは何もdtypeを指定しない状態で平均を計算。
Out[20]: 0.4961181909572322

In [21]: np.mean(d, dtype = "float32") # ビット数を半分にしてもう一度計算してみる。
Out[21]: 0.49611819

In [22]: np.mean(d, dtype = "float16") # 8ビットにするとさらに精度が低くなる
Out[22]: 0.49609

引数のoutについてですが、これはほとんど使用しません。メモリを使い回したいときに指定してください。

配列の次元数を落とさずに結果を求める

最後に、keepdimsについて解説します。keepdimsTrueを設定すると、軸の数を減らしません。次の例のように返された配列のshapeを見れば、どのような変化をするか分かりやすいです。

In [27]: b # 2次元配列のbを使用する。
Out[27]:
array([[1, 2, 2, 5, 1],
       [0, 9, 0, 4, 6],
       [4, 4, 8, 5, 5],
       [8, 3, 6, 2, 7]])


In [32]: e = np.mean(b, keepdims = True) # 次元を減らさない。

In [33]: e
Out[33]: array([[ 4.1]])

In [34]: e.shape
Out[34]: (1, 1)

In [35]: f = np.mean(b, keepdims = False)

In [36]: f
Out[36]: 4.0999999999999996

In [37]: g = np.mean(b, axis = 1, keepdims = True)

In [38]: g
Out[38]:
array([[ 2.2],
       [ 3.8],
       [ 5.2],
       [ 5.2]])

In [39]: g.shape
Out[39]: (4, 1)

In [40]: h = np.mean(b, axis = 1, keepdims = False)

In [41]: h
Out[41]: array([ 2.2,  3.8,  5.2,  5.2])

In [42]: h.shape
Out[42]: (4,)