NumPyのmean
関数は、配列の要素の平均を算出する関数です。デフォルトでは、配列を1次元化して全ての要素の平均を求めます。軸を指定した場合は、その軸方向に沿った要素の平均を求めます。
なお、NumPyには同じようなaverage関数という似た関数も用意されています。こちらは算術平均だけでなく、加重平均を求めることができます。mean関数では加重平均を求めることはできません。
しかしmean関数の方がオプション引数が多いため、その分、複雑な演算にも組み込みやすくなっています。基本的には、このmean関数を使い、加重平均が必要な場合にaverage関数を使うというようにうまく使い分けると良いでしょう。
それでは、mean関数を実際のコードで確認していきましょう。
NumPy配列の平均値の操作まとめ
NumPy配列の平均を操作する全方法については、『NumPyで平均値を求める3つの関数の使い方まとめ』ですべてまとめています。ぜひ一度ご確認ください。
1. 書式
それでは、まずは書き方を確認しましょう。
書き方:
np.mean(a, axis=None, dtype=None, out=None, keepdims=<no value>)
パラメーター:
引数 | 型 | 解説 |
a | array_like | ここで渡した配列の算術平均を求めます。 |
axis* | None または int もしくは tuple of ints |
算術平均を求める軸を指定します。デフォルトでは、配列を1次元にフラット化して平均を求めます。intのタプルを渡すと、複数の軸方向で平均を求めます。 |
dtype* | dtype | 戻り値のdtypeを指定します。通常は、元の配列のデータ型がint型の場合はfloat64型で戻されます。元の配列のデータ型がfloat型なら、例えば、float16ならfloat16、float32ならfloat32で戻されます。 |
out* | ndarray | これを指定すると、関数の戻り値で既存の配列を上書きすることができます。np.mean()の戻り値と、アウトプット先の配列のshapeは必ず一致している必要があります。 |
keepdims* | bool | これをTrueにすると、第一引数で渡した配列の次元数を維持します。そして、指定した軸のサイズは1になります。 |
* はオプション引数であることを示します。 |
戻り値:
ndarray: 平均値を要素とした新しい配列を戻します。 |
一緒に確認したい関数:
- average: 配列の要素の加重平均を取得
- std, var, nanmean, nanstd, nanvar
Note
mean
関数に渡す配列の要素が浮動小数点数の場合は、この関数は渡した配列のデータ型と同じ精度で演算を行います。そのためデータ型によっては、計算精度が粗い場合があります。特に、float32型はこの問題が起こりやすいです。その場合、dtypeを指定することで悪影響を軽減することができます。この点について、後で改めて触れたいと思います。
2. サンプルコード
それでは、サンプルコードを見ながら、実際の使い方を確認していきましょう。
算術平均を求める
以下の配列を例に見てみましょう。
import numpy as np
rng = np.random.default_rng()
x = rng.integers(1, 10, (5, ))
x
このランダムな整数を要素とする1次元配列x
を、np.mean
関数に渡すと、次のように平均値を戻します。
np.mean(x)
2次元配列以上のN次元配列を渡した場合も、デフォルトでは全要素の平均値を戻します。
# 2次元配列でも全体の平均値を求める
import numpy as np
rng = np.random.default_rng()
x = rng.integers(1, 10, (2, 3))
x
np.mean(x)
指定の軸方向の平均値を求める
オプション引数 axis=
を使うと、全要素の平均値ではなく、指定の軸方向の要素の平均値を求めることができます。
# 1次元軸(横軸)の要素の平均値を取得
np.mean(x, axis=1)
# 2次元軸(縦軸)の要素の平均値を取得
np.mean(x, axis=0)
データ型を指定
上のNoteでも触れていますが、np.mean
関数に要素が整数の配列を渡した場合、戻り値の型はfloat64型になります。そして、渡す配列のデータ型がfloat16型なら戻り値もfloat16型に、float32型の配列なら戻り値もfloat32型になります。
この特徴のため、時に計算結果が不正確になる場合があります。これは特にfloat32型の場合に見られます。
参考に以下のコードをご覧ください。
''' float型の場合、float64の方が正確 '''
# 2行512*512列の2次元配列を生成
arr = np.zeros((2, 512*512), dtype=np.float32)
# 1行目の全ての要素を1.0にする
arr[0:] = 1.0
# 2行目の全ての要素を0.1にする
arr[1:] = 0.1
# float32の場合の計算結果
print('float32: ', np.mean(arr))
# float64の場合の計算結果
print('float64: ', np.mean(arr, dtype=np.float64))
このコードでは、まず、shape(2, 512*512)の巨大な2次元配列を生成しています。そして、1行目の要素を全て1.0に、2行目の要素を全て0.1にしています。
そのため、平均値は(1.0+0.1)/2=0.55になります。しかし、実際の計算結果を見てみると、float32型とfloat64型では計算結果が異なり、後者の方が、より精密であることがわかります。
このような違いがあるので、出来るだけこの問題を軽減するために、より精密なデータ型(よりビット数の大きいデータ型)の配列で計算するようにすることをおすすめします。
なお、dtypeの一覧や指定する時の書き方などは、『NumPyのdtypeの一覧と確認・指定・変更方法』で解説していますのでご確認ください。
戻り値で既存の配列を上書き
np.mean関数
に、2次元以上のN次元配列を渡して、かつaxisを指定した場合、戻り値は配列として戻ってきます。
この時、その戻り値で既存の配列を上書きしたい場合、オプション引数 out=
でアウトプット先の配列を指定します。アウトプット先の配列と、関数の戻り値のshapeは一致している必要があります。
以下のコードをご覧ください。
''' 2次元配列でaxisを指定 '''
import numpy as np
# 2次元配列を生成
arr = np.random.randint(1, 10, (2, 5))
print('arr:\n', arr, '\n')
# アウトプット先の配列を生成
a_out = np.zeros(5)
print('a_out(関数実行前):\n', a_out, '\n')
# np.mean()の実行結果でa_outを上書き
np.mean(arr, axis=0, out=a_out)
# 関数実行後のa_outを出力
print('a_out(関数実行後):\n', a_out)
次元数を維持
2次元配列以上を渡した場合、np.mean
関数の戻り値の配列は、渡した配列の次元数-1になります。この時、元の配列の次元数を維持しておきたいならオプション引数keepdims=True
を指定します。
これを指定すると、指定したaxisを1にして、次元数を維持した上で、平均値を要素とした配列が戻ってきます。
つまり、例えば、shape(N, M)の2次元配列なら、axis=0なら戻り値の配列はshape(1, M)に、axis=1なら戻り値の配列はshape(N, 1)になります。
''' 2次元配列でaxisを指定 '''
# 2次元配列を生成
arr = np.random.randint(1, 10, (2, 5))
print('arr:\n', arr)
print('shape: ', arr.shape, '\n')
# axis=0
mean0 = np.mean(arr, axis=0, keepdims=True)
print('axis=0の場合:\n', mean0)
print('shape: ', mean0.shape, '\n')
# axis=1
mean1 = np.mean(arr, axis=1, keepdims=True)
print('axis=1の場合:\n', mean1)
print('shape: ', mean1.shape)
3. まとめ
以上が、NumPyのmean
関数の使い方です。特に難しい点はないかと思います。配列の要素の平均を求める際は積極的に使っていくと良いでしょう。
なお、冒頭でも述べましたが、加重平均が必要な時は、average
関数を使います。こちらは、『NumPyのaverage関数で配列の加重平均を取得する方法』で解説しています。
コメント