NumPy配列の平均計算はmean()が便利!今すぐ使える使い方
はじめに
データ分析、科学技術計算、機械学習など、Pythonを用いた様々な分野でNumPyは不可欠なライブラリとなっています。NumPyを使う最大の利点は、配列(ndarray)を効率的に扱える点にあります。特に、数値計算においては、Python標準のリストに比べて格段に高速であり、多様な計算を簡潔に記述できる機能が豊富に提供されています。
配列に対する基本的な統計計算の一つに「平均値の計算」があります。複数の数値の傾向を把握するために、平均値は非常によく使われる指標です。NumPyでは、この平均値計算のために非常に便利で強力なメソッドが提供されています。それがmean()
メソッドです。
Python標準機能でもリストの要素の合計を求めて要素数で割ることで平均値を計算することは可能ですが、NumPyのmean()
メソッドは、単に平均を計算するだけでなく、多次元配列の特定の軸に沿った平均を計算したり、結果のデータ型を指定したり、計算結果を特定の場所に格納したりといった、より高度な機能をシンプルに実現できます。
本記事では、NumPyのmean()
メソッドの基本的な使い方から、多次元配列におけるaxis
引数を使った応用、さらにdtype
、out
、keepdims
といった便利な引数の詳細な使い方まで、網羅的に解説します。この記事を読めば、NumPy配列の平均計算を効率的かつ柔軟に行えるようになり、データ分析や数値計算のスキルをさらに向上させることができるでしょう。
今すぐNumPyのmean()
メソッドを使いこなし、配列計算をより快適に、より強力に行いましょう!
NumPyの基礎を知る
mean()
メソッドを理解する前に、NumPyとその配列(ndarray)の基本的な概念を簡単に復習しておきましょう。既にNumPyに慣れている方は、このセクションをスキップして次のセクションに進んでも構いません。
NumPyとは? なぜ使うのか?
NumPy(Numerical Python)は、Pythonで数値計算を効率的に行うためのオープンソースライブラリです。特に、多次元配列の操作に特化しており、高速な配列演算機能を提供します。
Python標準のリストでも数値の集まりを扱うことはできますが、リストは柔軟性が高い反面、数値計算にはいくつかの弱点があります。
- 速度: リストは異なる型の要素を格納できるため、内部的なデータ構造が複雑になりがちです。大量の数値に対して繰り返し計算を行う場合、Pythonのループ処理はインタプリタ型言語の性質上、処理速度が遅くなる傾向があります。
- メモリ効率: リストは要素が分散してメモリに格納されることがあり、メモリ効率が悪くなる場合があります。
- 機能: リストには、数値計算に特化した組み込み関数やメソッドが少ないです。合計や平均を求めるには、
sum()
やlen()
を使って自分で計算する必要があります。
一方、NumPy配列(ndarray)は、以下の利点を持っています。
- 速度: ndarrayは固定されたデータ型の要素のみを保持し、メモリ上に連続して配置されます。これにより、データの読み書きが高速になり、さらにNumPyの多くの演算は内部的にC言語やFortranで実装されており、非常に高速に実行されます。いわゆる「ベクトル化演算」が可能になります。
- メモリ効率: ndarrayは要素が連続してメモリに配置されるため、メモリ効率が良いです。
- 機能: ndarrayオブジェクト自体に、様々な数学関数や統計関数(
sum()
,mean()
,std()
,max()
,min()
など)がメソッドとして備わっています。また、NumPyライブラリ自体にも豊富な関数(np.sin()
,np.cos()
,np.linalg.solve()
など)が用意されています。
これらの理由から、大規模な数値データを扱う場合や、繰り返し計算が必要な場合には、NumPyを使うことが強く推奨されます。
NumPy配列(ndarray)の作成方法
NumPy配列(ndarray)を作成するにはいくつかの方法があります。代表的なものを紹介します。
np.array()
: Pythonのリストやタプルから配列を作成します。
“`python
import numpy as np
1次元配列
list1 = [1, 2, 3, 4, 5]
arr1 = np.array(list1)
print(arr1)
[1 2 3 4 5]
2次元配列 (リストのリスト)
list2 = [[1, 2, 3], [4, 5, 6]]
arr2 = np.array(list2)
print(arr2)
[[1 2 3]
[4 5 6]]
“`
np.zeros()
: 指定した形状(shape)の、要素がすべて0の配列を作成します。
“`python
3×4のゼロ行列
arr_zeros = np.zeros((3, 4))
print(arr_zeros)
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
“`
np.ones()
: 指定した形状の、要素がすべて1の配列を作成します。
“`python
2×2のイチ行列
arr_ones = np.ones((2, 2))
print(arr_ones)
[[1. 1.]
[1. 1.]]
“`
np.arange()
: 指定した範囲の規則的な値を持つ配列を作成します。Pythonのrange()
に似ています。
“`python
0から9までの整数配列
arr_range = np.arange(10)
print(arr_range)
[0 1 2 3 4 5 6 7 8 9]
1から10まで、2ステップ
arr_range2 = np.arange(1, 11, 2)
print(arr_range2)
[1 3 5 7 9]
“`
np.linspace()
: 指定した範囲を、指定した個数で等分割する値を要素とする配列を作成します。
“`python
0から1までの範囲を5等分 (両端を含む5点)
arr_linspace = np.linspace(0, 1, 5)
print(arr_linspace)
[0. 0.25 0.5 0.75 1. ]
“`
配列の形状、次元数、要素数
ndarrayオブジェクトは、その構造に関する重要な属性を持っています。
.shape
: 配列の各次元の要素数をタプルで表します。例えば、3行4列の配列なら(3, 4)
となります。.ndim
: 配列の次元数(軸の数)を表します。.shape
タプルの要素数と同じです。1次元配列なら1、2次元配列なら2となります。.size
: 配列の全要素数を表します。.shape
の各要素を掛け合わせた値と同じです。
python
arr = np.array([[1, 2, 3], [4, 5, 6]])
print("Shape:", arr.shape) # (2, 3)
print("Ndim:", arr.ndim) # 2
print("Size:", arr.size) # 6
これらの基礎知識があれば、NumPy配列のmean()
メソッドの動作をより深く理解できます。
平均計算の基本
平均とは?
平均値(Arithmetic Mean)は、一連の数値データの中心的な傾向を示す代表値の一つです。定義としては、「データの合計値をデータの個数で割った値」となります。
例えば、データセット {10, 20, 30, 40, 50} の平均値は、
(10 + 20 + 30 + 40 + 50) / 5 = 150 / 5 = 30
となります。
NumPyを使わない場合の平均計算(Pythonリスト)
Pythonの標準機能を使ってリストの平均を計算するには、sum()
関数で合計を求め、len()
関数で要素数を求めて、それらを割り算します。
“`python
data_list = [10, 20, 30, 40, 50]
total = sum(data_list)
count = len(data_list)
average = total / count
print(f”リストの合計: {total}”)
print(f”リストの個数: {count}”)
print(f”リストの平均: {average}”)
リストの合計: 150
リストの個数: 5
リストの平均: 30.0
“`
これは簡単なリストであれば問題ありませんが、要素数が非常に多いリストや多次元構造を持つデータに対しては、いくつかの課題があります。前述の通り、速度やメモリ効率の面でNumPyに劣ります。また、多次元リストの特定の次元に沿った平均を計算しようとすると、複雑なループ処理を記述する必要があり、コードが読みにくく、間違いやすくなります。
なぜNumPyのmean()を使うべきか?
NumPyのmean()
メソッドを使用する最大の理由は、効率性と簡潔性です。
- 高速な計算: NumPyの内部実装により、大量のデータに対する平均計算が非常に高速です。特に大きな配列を扱う際には、Pythonリストを使った計算との速度差は歴然となります。
- シンプルなコード:
ndarray.mean()
やnp.mean(ndarray)
のように、メソッドまたは関数を呼び出すだけで平均が計算できます。 - 多次元配列のサポート: 多次元配列の特定の軸(行や列など)に沿った平均計算が、
axis
引数を指定するだけで簡単にできます。これにより、複雑なループ処理を書く必要がなくなります。 - 豊富なオプション: 結果のデータ型指定、NaN(非数)の無視、計算結果の格納先指定など、便利な機能が引数として提供されています。
これらの理由から、NumPy配列の平均計算にはmean()
メソッドを利用するのが最も効率的で推奨される方法です。
mean()メソッドの基本的な使い方
最も基本的なmean()
メソッドの使い方は、NumPy配列全体に渡る平均値を計算することです。これは、1次元配列でも多次元配列でも同様に機能します。
mean()
メソッドは、NumPy配列オブジェクトのメソッドとして呼び出す方法と、NumPyモジュールの関数として呼び出す方法があります。どちらを使っても同じ結果が得られます。
- メソッドとして呼び出す:
array_object.mean(...)
- 関数として呼び出す:
np.mean(array_object, ...)
通常はメソッドとして呼び出す方が一般的で、コードがよりオブジェクト指向的に見えます。
NumPy配列全体での平均計算
1次元配列の場合、mean()
メソッドは配列の全要素の平均値を計算します。
“`python
import numpy as np
1次元配列の例
arr1d = np.array([10, 20, 30, 40, 50])
mean()メソッドを使って平均を計算
mean_value = arr1d.mean()
print(f”1次元配列の平均: {mean_value}”)
1次元配列の平均: 30.0
np.mean()関数を使っても同じ
mean_value_func = np.mean(arr1d)
print(f”np.mean()を使った平均: {mean_value_func}”)
np.mean()を使った平均: 30.0
“`
多次元配列の場合も、axis
引数を指定しない場合(デフォルト)は、配列全体(全要素を平坦化した状態)の平均値を計算します。
“`python
import numpy as np
2次元配列の例
arr2d = np.array([[1, 2, 3],
[4, 5, 6]])
配列全体の平均を計算
mean_total = arr2d.mean()
print(f”2次元配列全体の平均: {mean_total}”)
2次元配列全体の平均: 3.5
(1+2+3+4+5+6) / 6 = 21 / 6 = 3.5
“`
このように、mean()
メソッドを使えば、配列の次元数に関わらず、非常に簡単に配列全体の平均値を求めることができます。計算結果は浮動小数点数(通常はfloat64
)となります。これは、整数同士の割り算で小数点以下の値が出る場合でも正確な結果を得るためです。
基本的な使い方はこれだけです。次に、多次元配列で非常に重要になるaxis
引数について詳しく見ていきましょう。
axis引数の使い方:多次元配列の部分平均計算
NumPy配列の強力な機能の一つは、多次元配列を効率的に扱えることです。特に、特定の「軸」に沿って計算を行う機能は、データ分析などで頻繁に使用されます。mean()
メソッドも、この軸指定の機能に対応しています。
axis
引数は、平均値を計算する際に「どの軸に沿って」要素をまとめるかを指定します。指定された軸は計算後に次元が圧縮される(またはサイズ1の次元として残る)と考えられます。
多次元配列の軸は、0から始まります。
- 1次元配列: 軸は0のみ。要素が並ぶ方向。
- 2次元配列(行列):
- 軸0: 行方向(上から下)。列ごとに要素をまとめる計算に使います。結果は行数が1の配列になります。
- 軸1: 列方向(左から右)。行ごとに要素をまとめる計算に使います。結果は列数が1の配列になります。
- 3次元配列:
- 軸0: 最初の次元(例えば「深さ」方向)。
- 軸1: 2番目の次元(「行」方向)。
- 軸2: 3番目の次元(「列」方向)。
axis=0を指定した場合(列方向の計算)
2次元配列(行列)でaxis=0
を指定すると、列ごとに平均値を計算します。つまり、各列の要素を縦方向に集めて平均を求めます。結果として得られる配列の次元数は、元の配列より1つ減少し、形状は元の.shape
からaxis=0に対応する次元を取り除いたものになります。
例: 2×3の配列
[[a, b, c],
[d, e, f]]
- axis=0で平均を計算すると、以下のようになります。
- 1列目の平均: (a + d) / 2
- 2列目の平均: (b + e) / 2
- 3列目の平均: (c + f) / 2
- 結果は、これらの平均値を要素とする1次元配列 [ (a+d)/2, (b+e)/2, (c+f)/2 ] となります。
- 元のshapeが
(2, 3)
の場合、axis=0を指定すると、軸0(サイズ2)が計算されてなくなり、結果のshapeは(3,)
となります。
コード例を見てみましょう。
“`python
import numpy as np
arr2d = np.array([[10, 20, 30],
[40, 50, 60]])
print(“元の配列:\n”, arr2d)
print(“元の配列のshape:”, arr2d.shape) # (2, 3)
axis=0を指定して平均を計算
mean_axis0 = arr2d.mean(axis=0)
print(“axis=0 で計算した平均:\n”, mean_axis0)
print(“axis=0 で計算した平均のshape:”, mean_axis0.shape) # (3,)
結果の確認
1列目の平均: (10 + 40) / 2 = 25
2列目の平均: (20 + 50) / 2 = 35
3列目の平均: (30 + 60) / 2 = 45
結果: [25. 35. 45.]
“`
axis=1を指定した場合(行方向の計算)
2次元配列(行列)でaxis=1
を指定すると、行ごとに平均値を計算します。つまり、各行の要素を横方向に集めて平均を求めます。結果として得られる配列の次元数は、元の配列より1つ減少し、形状は元の.shape
からaxis=1に対応する次元を取り除いたものになります。
例: 2×3の配列
[[a, b, c],
[d, e, f]]
- axis=1で平均を計算すると、以下のようになります。
- 1行目の平均: (a + b + c) / 3
- 2行目の平均: (d + e + f) / 3
- 結果は、これらの平均値を要素とする1次元配列 [ (a+b+c)/3, (d+e+f)/3 ] となります。
- 元のshapeが
(2, 3)
の場合、axis=1を指定すると、軸1(サイズ3)が計算されてなくなり、結果のshapeは(2,)
となります。
コード例を見てみましょう。
“`python
import numpy as np
arr2d = np.array([[10, 20, 30],
[40, 50, 60]])
print(“元の配列:\n”, arr2d)
print(“元の配列のshape:”, arr2d.shape) # (2, 3)
axis=1を指定して平均を計算
mean_axis1 = arr2d.mean(axis=1)
print(“axis=1 で計算した平均:\n”, mean_axis1)
print(“axis=1 で計算した平均のshape:”, mean_axis1.shape) # (2,)
結果の確認
1行目の平均: (10 + 20 + 30) / 3 = 60 / 3 = 20
2行目の平均: (40 + 50 + 60) / 3 = 150 / 3 = 50
結果: [20. 50.]
“`
axisを指定しない場合(デフォルト)
axis
引数を省略するか、axis=None
を指定した場合、mean()
は配列を平坦化(flatten)した上で全要素の平均値を計算します。これは、配列が1次元でも多次元でも同じ動作です。結果はスカラー値(NumPyのfloat64
などの0次元配列)になります。
“`python
import numpy as np
arr2d = np.array([[10, 20, 30],
[40, 50, 60]])
print(“元の配列:\n”, arr2d)
print(“元の配列のshape:”, arr2d.shape) # (2, 3)
axisを指定しない場合 (デフォルト)
mean_total = arr2d.mean()
print(“axis指定なし (全体) で計算した平均:”, mean_total)
print(“axis指定なし (全体) で計算した平均の型:”, type(mean_total)) #
axis=None を指定した場合も同じ
mean_total_none = arr2d.mean(axis=None)
print(“axis=None で計算した平均:”, mean_total_none)
“`
3次元配列でのaxisの使い方
axis
引数は3次元以上の配列でも同様に使えます。3次元配列は、例えば形状が(d, h, w)
である場合、「深さ d」×「高さ h」×「幅 w」を持つと考えられます。
axis=0
: 深さ方向の計算。各(h, w)
スライスに対して、その位置にあるd
個の要素の平均を取ります。結果のshapeは(h, w)
になります。axis=1
: 高さ方向の計算。各(d, w)
スライスに対して、その位置にあるh
個の要素の平均を取ります。結果のshapeは(d, w)
になります。axis=2
: 幅方向の計算。各(d, h)
スライスに対して、その位置にあるw
個の要素の平均を取ります。結果のshapeは(d, h)
になります。
複数の軸を同時に指定することも可能です。この場合、指定した全ての軸に沿って平均を計算します。axis
にはタプルで軸インデックスを渡します。
例: 3次元配列 (2x3x4)
“`python
import numpy as np
3次元配列 (2つの2×4の「層」を持つ3×4の行列)
shape: (2, 3, 4)
軸0: 2 (層の数)
軸1: 3 (行の数)
軸2: 4 (列の数)
arr3d = np.arange(24).reshape(2, 3, 4)
print(“元の3次元配列:\n”, arr3d)
print(“元の配列のshape:”, arr3d.shape) # (2, 3, 4)
axis=0 で計算 (層ごとの平均)
mean_axis0 = arr3d.mean(axis=0)
print(“\naxis=0 で計算した平均 (shape: %s):\n” % (mean_axis0.shape,), mean_axis0)
結果shape: (3, 4)
例: 結果[0, 0] = (arr3d[0, 0, 0] + arr3d[1, 0, 0]) / 2 = (0 + 12) / 2 = 6
axis=1 で計算 (行ごとの平均, 層と列は維持)
mean_axis1 = arr3d.mean(axis=1)
print(“\naxis=1 で計算した平均 (shape: %s):\n” % (mean_axis1.shape,), mean_axis1)
結果shape: (2, 4)
例: 結果[0, 0] = (arr3d[0, 0, 0] + arr3d[0, 1, 0] + arr3d[0, 2, 0]) / 3 = (0 + 4 + 8) / 3 = 12/3 = 4
axis=2 で計算 (列ごとの平均, 層と行は維持)
mean_axis2 = arr3d.mean(axis=2)
print(“\naxis=2 で計算した平均 (shape: %s):\n” % (mean_axis2.shape,), mean_axis2)
結果shape: (2, 3)
例: 結果[0, 0] = (arr3d[0, 0, 0] + arr3d[0, 0, 1] + arr3d[0, 0, 2] + arr3d[0, 0, 3]) / 4 = (0 + 1 + 2 + 3) / 4 = 6/4 = 1.5
複数の軸を同時に指定 (axis=(0, 1) で計算)
これは、軸0と軸1をまとめて計算することを意味します。
2×3 の各「層」/「行」グループについて、軸2 (列) に沿った平均を計算せず、
その2×3の範囲の全要素の平均を求めます。
結果のshapeは元のshape (2, 3, 4) から軸0(サイズ2)と軸1(サイズ3)を取り除いたものになります。
つまり、shape (4,) となります。
mean_axis01 = arr3d.mean(axis=(0, 1))
print(“\naxis=(0, 1) で計算した平均 (shape: %s):\n” % (mean_axis01.shape,), mean_axis01)
結果shape: (4,)
例: 結果[0] = 全ての arr3d[i, j, 0] の平均 = (arr3d[0,0,0]+arr3d[0,1,0]+arr3d[0,2,0] + arr3d[1,0,0]+arr3d[1,1,0]+arr3d[1,2,0]) / 6
= (0+4+8 + 12+16+20) / 6 = 60 / 6 = 10
3つの軸全てを指定 (axis=(0, 1, 2)) は axis=None と同じ、全体平均になります。
mean_axis_all = arr3d.mean(axis=(0, 1, 2))
print(“\naxis=(0, 1, 2) で計算した平均:”, mean_axis_all)
print(“全体平均 (axis=None) と比較:”, arr3d.mean(axis=None))
結果: 11.5 (0から23までの平均は (0+23)/2 = 11.5)
“`
axis
引数は、データを行列として扱う際に非常に便利です。例えば、データセットが行方向にサンプル、列方向に対応する特徴量を持つ場合、axis=0
で計算すると各特徴量の平均が得られ、axis=1
で計算すると各サンプルの特徴量の平均が得られます。
負の軸インデックス
Pythonのリストのスライスと同様に、NumPyの軸インデックスも負の値を使用できます。負のインデックスは末尾からカウントされます。
axis=-1
: 最後の軸axis=-2
: 最後から2番目の軸- …といった具合です。
例えば、2次元配列(shape (m, n)
) の場合、axis=0
はaxis=-2
、axis=1
はaxis=-1
と等価です。3次元配列(shape (d, h, w)
) の場合、axis=0
はaxis=-3
、axis=1
はaxis=-2
、axis=2
はaxis=-1
と等価です。
これは、配列の次元数が動的に変わるようなコードを書く場合に便利です。例えば、常に最後の軸に沿って計算したい場合は、配列の次元数に関わらずaxis=-1
を指定すればよいのです。
“`python
import numpy as np
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
arr3d = np.arange(24).reshape(2, 3, 4)
print(“arr2d shape:”, arr2d.shape) # (2, 3)
print(“arr2d mean(axis=1):\n”, arr2d.mean(axis=1))
print(“arr2d mean(axis=-1):\n”, arr2d.mean(axis=-1)) # axis=1 と同じ結果
print(“\narr3d shape:”, arr3d.shape) # (2, 3, 4)
print(“arr3d mean(axis=0):\n”, arr3d.mean(axis=0)[0, 0]) # 例として最初の要素のみ
print(“arr3d mean(axis=-3):\n”, arr3d.mean(axis=-3)[0, 0]) # axis=0 と同じ結果 (最初の要素のみ)
“`
このようにaxis
引数を使いこなすことで、NumPy配列の平均計算を非常に柔軟に行うことができます。これはNumPyのmean()
メソッドの最も重要な機能の一つです。
dtype引数の使い方:計算結果のデータ型を指定する
mean()
メソッドのもう一つの便利な引数にdtype
があります。これは、平均計算を行う際に使用するデータ型や、計算結果のデータ型を指定するために使用されます。
NumPy配列の要素は特定のデータ型(整数、浮動小数点数など)を持っています。例えば、int64
やfloat64
などです。平均計算は通常、割り算を含むため、小数点以下の値が発生する可能性があります。
デフォルトの挙動
デフォルトでは、mean()
メソッドは計算を実行する際に、必要に応じて要素をより高精度な浮動小数点型にアップキャスト(変換)します。例えば、整数の配列であっても、中間計算や最終結果は浮動小数点型(通常はfloat64
)になります。これは、整数割り算によって小数点以下が切り捨てられるのを防ぎ、正確な平均値を保証するためです。
“`python
import numpy as np
整数の配列
arr_int = np.array([1, 2, 3, 4, 5], dtype=np.int64)
print(“元の配列のdtype:”, arr_int.dtype)
平均計算 – 結果は浮動小数点型になる
mean_value = arr_int.mean()
print(“平均値:”, mean_value)
print(“平均値のdtype:”, type(mean_value)) #
print(“平均値のdtype (numpy):”, mean_value.dtype if isinstance(mean_value, np.ndarray) else type(mean_value)) #
浮動小数点数の配列
arr_float = np.array([1.0, 2.5, 3.0, 4.5])
print(“\n元の配列のdtype:”, arr_float.dtype)
平均計算 – 結果は浮動小数点型のまま
mean_value_float = arr_float.mean()
print(“平均値:”, mean_value_float)
print(“平均値のdtype:”, mean_value_float.dtype if isinstance(mean_value_float, np.ndarray) else type(mean_value_float))
平均値のdtype (numpy): float64
“`
dtypeを指定する理由
デフォルトの挙動でほとんどの場合は問題ありませんが、特定のデータ型で計算を行いたい場合や、結果を特定のデータ型で得たい場合にdtype
引数を使用します。
- 計算の精度を制御: 例えば、単精度浮動小数点数(
float32
)で十分な場合や、メモリを節約したい場合に指定できます。 - 結果のデータ型を明示的に指定: 計算結果を特定の型で受け取りたい場合に指定します。
- 整数での平均計算(非推奨だが可能性として):
dtype
に整数型を指定すると、平均計算も整数として行われる「可能性」があります。ただし、これは通常意図しない結果(小数点以下の切り捨て)を招くため、特別な理由がない限り、平均計算でdtypeに整数型を指定すべきではありません。
例:float32
で計算と結果を得る
“`python
import numpy as np
arr_float64 = np.array([1.1, 2.2, 3.3], dtype=np.float64)
print(“元の配列のdtype:”, arr_float64.dtype)
dtypeにfloat32を指定して平均計算
mean_float32 = arr_float64.mean(dtype=np.float32)
print(“float32で計算した平均:”, mean_float32)
print(“結果のdtype:”, mean_float32.dtype if isinstance(mean_float32, np.ndarray) else type(mean_float32))
結果のdtype: float32
“`
例:整数dtypeを指定した場合の注意
“`python
import numpy as np
arr_int = np.array([1, 2, 3, 4]) # dtypeはint64 (デフォルト)
print(“元の配列:”, arr_int)
デフォルト (float64) で計算 -> 正しい平均値
mean_default = arr_int.mean()
print(“デフォルトdtypeでの平均:”, mean_default) # 2.5
dtype=np.int64 を指定して計算 -> 意図しない結果になる可能性
NumPyの内部実装によりますが、多くの場合、計算前にint64にキャストされてから計算が行われるため、
中間合計はint64で行われ、割り算も整数割り算になります。
ただし、mean()は通常、計算過程でより広い型にアップキャストされるため、
直接的にint64を指定しても、デフォルトと同じfloat64になることが多いです。
しかし、他の関数や古いバージョンでは異なる挙動を示すこともあります。
平均計算でintを指定するのは、小数点以下が不要な場合など、特定の目的がある場合のみにすべきです。
例として、計算結果を強制的にintにする場合は、mean()の後に型変換を行います。
mean_as_int = arr_int.mean().astype(np.int64)
print(“結果をintにキャストした平均:”, mean_as_int) # 2 (小数点以下が切り捨てられる)
結論として、平均計算にはデフォルトの浮動小数点型を使用するのが最も安全で正確です。
意図的に整数結果が欲しい場合は、計算後にastype()で型変換するのが良いでしょう。
“`
dtype
引数は、主に計算精度やメモリ使用量の制御、あるいは特定の後続処理のために結果の型を明示的に指定したい場合に役立ちます。通常はデフォルトのままで問題ありません。
out引数の使い方:計算結果を特定の配列に格納する
mean()
メソッドは計算結果を新しいNumPy配列として返しますが、out
引数を使用すると、あらかじめ用意しておいたNumPy配列に計算結果を格納することができます。
これは、特に大規模な計算を繰り返し行う場合や、メモリ割り当てを最適化したい場合に有用です。結果を格納する配列を使い回すことで、新しい配列を頻繁に作成するオーバーヘッドを減らすことができます。
out
引数に指定できる配列は、以下の条件を満たす必要があります。
- 形状 (shape): 格納先の配列の形状は、計算結果の形状と一致している必要があります。例えば、2×3の配列の
axis=0
での平均計算結果はshape(3,)
になるので、out
に指定する配列もshape(3,)
である必要があります。 - データ型 (dtype): 格納先の配列のデータ型は、計算結果のデータ型と互換性がある必要があります。通常、
mean()
のデフォルトの戻り値型(float64
など)か、dtype
引数で指定した型を受け入れられる型である必要があります。 - C連続メモリ配置: 格納先の配列は、通常C-contiguousである必要があります(必須ではない場合もありますが、推奨されます)。
例を見てみましょう。
“`python
import numpy as np
arr2d = np.array([[10, 20, 30],
[40, 50, 60]], dtype=np.float64) # デモのためfloat64に
axis=0 で計算する平均の shape は (3,)
結果を格納するための配列を shape (3,) で用意する
dtypeはmean()のデフォルト(float64)か互換性のある型にする
out_arr_axis0 = np.zeros(3, dtype=np.float64)
print(“格納先の配列 (axis=0):”, out_arr_axis0)
mean()のout引数に格納先の配列を指定して計算
arr2d.mean(axis=0, out=out_arr_axis0)
print(“計算後の格納先の配列 (axis=0):\n”, out_arr_axis0)
結果は [25. 35. 45.] となり、out_arr_axis0 に格納される
axis=1 で計算する平均の shape は (2,)
out_arr_axis1 = np.zeros(2, dtype=np.float64)
print(“\n格納先の配列 (axis=1):”, out_arr_axis1)
mean()のout引数に格納先の配列を指定して計算
arr2d.mean(axis=1, out=out_arr_axis1)
print(“計算後の格納先の配列 (axis=1):\n”, out_arr_axis1)
結果は [20. 50.] となり、out_arr_axis1 に格納される
配列全体での計算の場合、結果はスカラー (shape は ())
この場合、out引数には shape が () のNumPy配列(0次元配列)を指定する必要があります。
out_scalar = np.zeros((), dtype=np.float64)
print(“\n格納先のスカラー配列:”, out_scalar)
mean()のout引数に格納先のスカラー配列を指定して計算
arr2d.mean(out=out_scalar)
print(“計算後の格納先のスカラー配列:”, out_scalar)
結果は 3.5 となり、out_scalar に格納される
print(“格納された値:”, out_scalar.item()) # .item() でスカラー値を取り出せる
“`
out
引数は、特に大規模な配列を扱い、メモリの確保・解放のコストを抑えたい場合に有効です。通常の用途であれば、out
引数を使わずに新しい配列として結果を受け取っても問題ありません。
keepdims引数の使い方:結果の次元を維持する
keepdims
引数は、mean()
メソッドで計算した結果の配列の次元数を、元の配列と同じに保つかどうかを制御します。デフォルトはFalse
です。
keepdims=False
(デフォルト): 平均を計算した軸に対応する次元は、結果の配列から削除されます。例えば、shape(2, 3)
の配列に対してaxis=0
で計算すると、結果は shape(3,)
の1次元配列になります。keepdims=True
: 平均を計算した軸に対応する次元は削除されず、サイズ1の次元として結果の配列に残されます。例えば、shape(2, 3)
の配列に対してaxis=0
で計算すると、結果は shape(1, 3)
の2次元配列になります。
この引数は、計算結果を元の配列と同じ次元数で保持したい場合や、ブロードキャスト機能を使って計算結果と元の配列を演算する場合に非常に便利です。
例を見てみましょう。
“`python
import numpy as np
arr2d = np.array([[10, 20, 30],
[40, 50, 60]])
print(“元の配列:\n”, arr2d)
print(“元の配列のshape:”, arr2d.shape) # (2, 3)
axis=0 で計算, keepdims=False (デフォルト)
mean_axis0_no_keep = arr2d.mean(axis=0, keepdims=False)
print(“\naxis=0, keepdims=False で計算した平均:\n”, mean_axis0_no_keep)
print(“shape:”, mean_axis0_no_keep.shape) # (3,)
axis=0 で計算, keepdims=True
mean_axis0_keep = arr2d.mean(axis=0, keepdims=True)
print(“\naxis=0, keepdims=True で計算した平均:\n”, mean_axis0_keep)
print(“shape:”, mean_axis0_keep.shape) # (1, 3)
結果は [[25. 35. 45.]] となり、[25. 35. 45.] ではなく、形状が (1, 3) の2次元配列になる
axis=1 で計算, keepdims=False (デフォルト)
mean_axis1_no_keep = arr2d.mean(axis=1, keepdims=False)
print(“\naxis=1, keepdims=False で計算した平均:\n”, mean_axis1_no_keep)
print(“shape:”, mean_axis1_no_keep.shape) # (2,)
axis=1 で計算, keepdims=True
mean_axis1_keep = arr2d.mean(axis=1, keepdims=True)
print(“\naxis=1, keepdims=True で計算した平均:\n”, mean_axis1_keep)
print(“shape:”, mean_axis1_keep.shape) # (2, 1)
結果は [[20.], [50.]] となり、[20., 50.] ではなく、形状が (2, 1) の2次元配列になる
axis=None (全体平均), keepdims=False (デフォルト)
mean_total_no_keep = arr2d.mean(axis=None, keepdims=False)
print(“\naxis=None, keepdims=False で計算した平均:”, mean_total_no_keep)
print(“shape:”, mean_total_no_keep.shape) # () – スカラー値 (0次元配列)
axis=None (全体平均), keepdims=True
mean_total_keep = arr2d.mean(axis=None, keepdims=True)
print(“\naxis=None, keepdims=True で計算した平均:”, mean_total_keep)
print(“shape:”, mean_total_keep.shape) # (1, 1)
結果は [[3.5]] となり、形状が (1, 1) の2次元配列になる
“`
keepdims=True の利便性:ブロードキャストとの組み合わせ
keepdims=True
が特に役立つのは、計算結果を使って元の配列の各要素から平均を引くなど、ブロードキャストを利用した演算を行いたい場合です。
NumPyのブロードキャスト機能は、形状が異なる配列間での演算を可能にします。演算は、サイズ1の次元を拡大したり、後続の次元を一致させたりすることで行われます。
例:配列の各要素から列平均を引く(データのセンタリング)
元の配列: arr2d
(shape: (2, 3)
)
列平均 (axis=0):
* keepdims=False
の場合: mean_axis0_no_keep
(shape: (3,)
)
* keepdims=True
の場合: mean_axis0_keep
(shape: (1, 3)
)
元の配列 (2, 3)
から列平均を引く演算を考えます。
arr2d - column_means
-
arr2d
(2, 3) とmean_axis0_no_keep
(3,) で減算を行う場合:
NumPyはブロードキャスト規則に従います。後続の次元から比較すると、3
と3
は一致します。しかし、その前の次元は2
と、片方は次元がありません。NumPyは次元のない方を前に追加して考えますが、結局(2, 3)
と(3,)
はそのままではブロードキャスト可能ではありません。意図通りに列ごとの引き算を行うには、mean_axis0_no_keep
のshapeを(1, 3)
のように変更する必要があります(例:mean_axis0_no_keep[np.newaxis, :]
)。 -
arr2d
(2, 3) とmean_axis0_keep
(1, 3) で減算を行う場合:
後続の次元から比較します。3
と3
は一致します。その前の次元は2
と1
です。NumPyのブロードキャスト規則では、どちらかの次元が1であれば、もう一方の次元数に合わせて拡大されます。したがって、shape(1, 3)
の配列は shape(2, 3)
にブロードキャストされます。具体的には、 shape(1, 3)
の配列が縦方向に繰り返されて、元の配列と同じ shape になったかのように扱われます。
このブロードキャストの挙動により、keepdims=True
で得られた shape (1, 3)
の列平均配列は、元の配列 (2, 3)
から、それぞれの列に対応する平均値が適切に引き算されることになります。
“`python
import numpy as np
arr2d = np.array([[10, 20, 30],
[40, 50, 60]], dtype=np.float64)
列平均を keepdims=True で計算
mean_axis0_keep = arr2d.mean(axis=0, keepdims=True)
print(“列平均 (keepdims=True, shape %s):\n” % (mean_axis0_keep.shape,), mean_axis0_keep)
結果: [[25. 35. 45.]] shape (1, 3)
元の配列から列平均を引く (ブロードキャストが働く)
centered_arr = arr2d – mean_axis0_keep
print(“\n元の配列から列平均を引いた結果:\n”, centered_arr)
結果:
[[10 – 25, 20 – 35, 30 – 45],
[40 – 25, 50 – 35, 60 – 45]]
= [[-15. -15. -15.]
[ 15. 15. 15.]]
各列の平均がほぼ0になっていることを確認
print(“\nセンタリング後の各列の平均:”, centered_arr.mean(axis=0))
結果: [0. 0. 0.] (浮動小数点の誤差で非常に小さい値になることもあります)
“`
このように、keepdims=True
は、軸に沿った統計量(平均、合計、標準偏差など)を計算し、その結果を使って元の配列に対して何らかの変換(センタリング、標準化など)を行いたい場合に非常に有用です。結果の配列が元の配列と同じ次元数を持ち、計算で圧縮された軸がサイズ1で保持されることで、NumPyのブロードキャスト機能が自然に機能するようになります。
mean()メソッドの応用例
mean()
メソッドは、様々なデータ処理や分析タスクで中心的な役割を果たします。いくつかの応用例を見てみましょう。
データ分析における平均(中央傾向の把握)
最も基本的な応用は、データセットの代表値として平均を求めることです。NumPy配列として読み込まれた数値データの平均、あるいはデータフレームの一部(列など)をNumPy配列として取り出して平均を計算します。
“`python
import numpy as np
import pandas as pd
例: Pandas DataFrame
data = {‘Column1’: np.random.rand(100),
‘Column2’: np.random.randint(0, 100, 100),
‘Column3’: np.random.randn(100)}
df = pd.DataFrame(data)
DataFrameの特定の列の平均をNumPy配列として計算
col1_mean = df[‘Column1’].values.mean()
print(f”Column1 の平均: {col1_mean:.4f}”)
DataFrame全体の平均 (各列の平均をNumPy配列として取得し、さらにその平均)
または DataFrame.mean() を使うのが一般的ですが、ここではNumPyのmean()を意識して記述
df_values = df.values # DataFrame全体をNumPy配列として取得 (shape: 100, 3)
total_mean = df_values.mean()
print(f”DataFrame全体の平均 (全要素): {total_mean:.4f}”)
各列の平均 (axis=0)
column_means = df_values.mean(axis=0)
print(f”各列の平均:\n {column_means}”)
各行の平均 (axis=1)
row_means = df_values.mean(axis=1)
print(f”各行の平均 (最初の5つ):\n {row_means[:5]}…”)
“`
画像処理における平均
画像は通常、NumPy配列(高さ x 幅 x チャンネル数)として扱われます。例えば、RGB画像は shape が (height, width, 3)
の3次元配列になります。mean()
メソッドを使って、画像に関する様々な平均値を計算できます。
- 画像全体の平均輝度: 配列全体の平均 (
axis=None
) を計算します。グレースケール画像なら平均輝度、カラー画像なら全ピクセルの全チャンネルの平均値。 - チャンネルごとの平均輝度:
axis=(0, 1)
を指定して、高さ軸と幅軸に沿って平均を計算します。これにより、各チャンネル(R, G, B)の平均輝度が得られます。
“`python
import numpy as np
簡単な擬似カラー画像データ (高さ2, 幅3, チャンネル3)
shape: (2, 3, 3)
軸0: 高さ (2)
軸1: 幅 (3)
軸2: チャンネル (3 – R, G, B)
image_data = np.array([[[255, 0, 0], [0, 255, 0], [0, 0, 255]], # 1行目 (赤、緑、青)
[[100, 100, 100], [50, 50, 50], [200, 200, 200]]], # 2行目 (灰色いろいろ)
dtype=np.uint8) # 画像データは通常uint8
print(“擬似画像データ (shape %s):\n” % (image_data.shape,), image_data)
画像全体の平均値 (全ピクセルの全チャンネルの平均)
デフォルトでは結果がfloatになるので、astypeでintに丸めることも可能
mean_total = image_data.mean().astype(np.uint8) # 結果をuint8に戻す
print(“\n画像全体の平均値:”, mean_total)
(255+0+0 + 0+255+0 + 0+0+255 + 100+100+100 + 50+50+50 + 200+200+200) / 18
= (2553 + 1003 + 503 + 2003) / 18
= (765 + 300 + 150 + 600) / 18 = 1815 / 18 = 100.83… -> 100
チャンネルごとの平均輝度 (高さと幅の軸で平均)
axis=(0, 1) で計算し、結果の形状は (3,) となる (チャンネル数に対応)
keepdims=True にすると形状は (1, 1, 3) となる
mean_channels = image_data.mean(axis=(0, 1))
print(“\nチャンネルごとの平均輝度 (shape %s):” % (mean_channels.shape,), mean_channels)
Rチャンネルの平均: (255 + 100) / 2 = 177.5
Gチャンネルの平均: (0 + 50) / 2 = 25.0
Bチャンネルの平均: (0 + 200) / 2 = 100.0
結果: [177.5 25. 100. ]
mean_channels_keep = image_data.mean(axis=(0, 1), keepdims=True)
print(“\nチャンネルごとの平均輝度 (keepdims=True, shape %s):\n” % (mean_channels_keep.shape,), mean_channels_keep)
結果: [[[177.5 25. 100. ]]] shape (1, 1, 3) – ブロードキャストなどに便利
“`
特定の条件を満たす要素の平均
NumPyのブールインデックス(条件式を使って要素を抽出する機能)と組み合わせることで、特定の条件を満たす要素のみの平均を計算できます。
“`python
import numpy as np
arr = np.array([10, 15, 20, 25, 30, -5, 0, 50, 100])
0より大きい要素の平均
positive_elements = arr[arr > 0]
mean_positive = positive_elements.mean()
print(f”0より大きい要素: {positive_elements}”)
print(f”0より大きい要素の平均: {mean_positive}”)
偶数の要素の平均
% 2 == 0 で偶数判定
even_elements = arr[arr % 2 == 0]
mean_even = even_elements.mean()
print(f”\n偶数の要素: {even_elements}”)
print(f”偶数の要素の平均: {mean_even}”)
“`
このように、mean()
メソッドは、NumPy配列の柔軟なインデックス機能と組み合わせることで、非常に多様な計算ニーズに対応できます。
mean()と関連する関数
NumPyには、平均に関連するいくつかの関数があります。mean()
とどのように違うのか、見てみましょう。
np.average()
(重み付き平均)
np.average()
関数は、重み付き平均を計算できます。各要素に異なる重要度(重み)を与えて平均を求めたい場合に利用します。重みを指定しない場合は、np.mean()
と同じく通常の平均を計算します。
“`python
import numpy as np
data = np.array([10, 20, 30, 40, 50])
weights = np.array([1, 1, 1, 1, 1]) # 各要素の重みが等しい場合
重み付き平均 (重みが等しいので通常平均と同じ)
avg_weighted_equal = np.average(data, weights=weights)
print(f”重み付き平均 (重み等しい): {avg_weighted_equal}”)
print(f”np.mean() と比較: {np.mean(data)}”)
特定の要素に重みを与える場合
weights_custom = np.array([1, 1, 5, 1, 1]) # 30に重み5を与える
avg_weighted_custom = np.average(data, weights=weights_custom)
print(f”重み付き平均 (カスタム重み): {avg_weighted_custom}”)
計算: (101 + 201 + 305 + 401 + 50*1) / (1+1+5+1+1)
= (10 + 20 + 150 + 40 + 50) / 9
= 270 / 9 = 30.0
“`
np.average()
はaxis
引数もサポートしています。また、returned=True
引数を指定すると、重みの合計値も一緒に返すことができます。
np.median()
(中央値)
中央値は、データを小さい順に並べたときに真ん中にくる値です。平均値と同様にデータの中心傾向を示しますが、外れ値の影響を受けにくいという特徴があります。
“`python
import numpy as np
data1 = np.array([1, 2, 3, 4, 5])
data2 = np.array([1, 2, 3, 4, 5, 100]) # 外れ値を含む
print(f”データ1: {data1}”)
print(f”データ1の平均: {np.mean(data1)}”) # 3.0
print(f”データ1の中央値: {np.median(data1)}”) # 3.0 (真ん中の値)
print(f”\nデータ2: {data2}”)
print(f”データ2の平均: {np.mean(data2)}”) # (1+2+3+4+5+100)/6 = 115/6 = 19.16…
print(f”データ2の中央値: {np.median(data2)}”) # (3+4)/2 = 3.5 (真ん中の2つの平均)
“`
np.median()
もaxis
引数をサポートしており、多次元配列の特定軸に沿った中央値を計算できます。
np.std()
(標準偏差) と np.var()
(分散)
標準偏差と分散は、データの散らばり具合を示す指標です。標準偏差は分散の平方根です。
“`python
import numpy as np
data = np.array([10, 20, 30, 40, 50])
print(f”データ: {data}”)
print(f”平均: {np.mean(data)}”)
print(f”標準偏差: {np.std(data)}”) # データが平均からどれだけ散らばっているか
print(f”分散: {np.var(data)}”) # 標準偏差の2乗
“`
これらの関数もaxis
引数をサポートしており、mean()
と同様に特定の軸に沿った統計量を計算できます。また、標本標準偏差/分散と母標準偏差/分散を切り替えるためのddof
引数も持っています(デフォルトはddof=0
で標本分散に相当する不偏分散ではなく、単にNで割った値になります。統計学でよく使う不偏分散や不偏標準偏差を求めるにはddof=1
を指定します)。
mean()
、average()
、median()
、std()
、var()
といった関数は、NumPyを使ったデータ分析において、データセットの特性を理解するための基本的なツールとなります。これらの関数は、NumPy配列のメソッドとしても提供されています。
パフォーマンス
前述の通り、NumPyのmean()
メソッドがPythonリストでの計算に比べて圧倒的に高速であることは、NumPyを使う大きな理由の一つです。この速度差は、主に以下の要因によります。
- ベクトル化演算: NumPyの演算は、要素ごとにPythonのループで処理するのではなく、配列全体に対して一度に処理を行います。これは「ベクトル化」と呼ばれ、内部的に高度に最適化された低レベル言語(C, Fortranなど)で実装されています。
- 連続メモリ配置: NumPy配列は要素がメモリ上に連続して配置されるため、CPUのキャッシュ効率が向上し、データへのアクセスが高速になります。
- 単一データ型: NumPy配列の要素はすべて同じデータ型であるため、型チェックのオーバーヘッドがなくなり、より効率的な計算が可能になります。
簡単な例で速度の違いを体感してみましょう。
“`python
import numpy as np
import time
非常に大きなデータを用意
size = 10_000_000 # 1000万個の要素
Pythonリスト
python_list = list(range(size))
NumPy配列
numpy_array = np.arange(size)
Pythonリストでの平均計算
start_time = time.time()
total = sum(python_list)
count = len(python_list)
mean_python = total / count
end_time = time.time()
print(f”Pythonリストでの平均計算時間: {end_time – start_time:.6f} 秒”)
NumPy配列での平均計算
start_time = time.time()
mean_numpy = numpy_array.mean()
end_time = time.time()
print(f”NumPy配列での平均計算時間: {end_time – start_time:.6f} 秒”)
print(f”平均値の比較: Python={mean_python}, NumPy={mean_numpy}”)
“`
このコードを実行すると、NumPyを使った平均計算がPythonリストを使った計算よりもはるかに高速であることが確認できるはずです。データサイズが大きくなるほど、その差は顕著になります。
データ分析や科学技術計算では大規模なデータを扱うことが多いため、NumPyの高速な計算機能は必須となります。mean()
メソッドもその恩恵を最大限に受けている機能の一つです。
注意点とトラブルシューティング
mean()
メソッドを使用する際に遭遇する可能性がある注意点や、一般的なトラブルシューティングについて解説します。
データ型による結果の違い(整数 vs 浮動小数点)
既にdtype
のセクションで触れましたが、元の配列のデータ型が整数型の場合、割り算を含む平均計算の過程で意図しない結果(小数点以下の切り捨て)が発生しないように注意が必要です。mean()
のデフォルトの挙動は計算結果を浮動小数点型にするため安全ですが、例えば自分で合計と個数を求めてから割り算する場合などは、どちらか一方を浮動小数点型にキャストする必要があります。
“`python
import numpy as np
arr_int = np.array([1, 2, 3, 4])
NumPyのmean()を使う (安全)
mean_safe = arr_int.mean()
print(f”NumPy mean() での平均: {mean_safe}”) # 2.5
Pythonの sum() と len() + 整数割り算 (危険)
total = sum(arr_int) # total は int (10)
count = len(arr_int) # count は int (4)
mean_unsafe = total // count # Python 3 では // は整数割り算
print(f”整数割り算での平均: {mean_unsafe}”) # 2 (小数点以下が切り捨てられる)
安全なPythonの方法 (floatにキャスト)
total = sum(arr_int)
count = len(arr_int)
mean_safe_python = total / count # Python 3 では / は常に浮動小数点割り算
print(f”Pythonでの安全な平均: {mean_safe_python}”) # 2.5
“`
NumPyのmean()
を使う限り、デフォルトでは結果が浮動小数点型になるため、この問題はほとんど発生しませんが、内部的な計算プロセスを理解しておくことは重要です。
NaN(非数)の扱い
データの中にNaN(Not a Number、非数)が含まれている場合、mean()
メソッドはデフォルトでNaNを含む結果を返します。これは、NaNがどのような数値計算の結果もNaNにするというNumPyの一般的なルールに従うためです。
データ分析では欠損値がNaNとして表現されることがよくあります。NaNを無視して有効な数値のみの平均を計算したい場合は、numpy.nanmean()
関数を使用します。
“`python
import numpy as np
data_with_nan = np.array([10, 20, np.nan, 40, 50])
print(f”NaNを含むデータ: {data_with_nan}”)
mean() を使うと NaN が結果に含まれる
mean_with_nan = np.mean(data_with_nan)
print(f”mean() での平均 (NaNを含む): {mean_with_nan}”) # nan
nanmean() を使うと NaN を無視して計算
np.nanmean([10, 20, 40, 50]) -> (10+20+40+50) / 4 = 120 / 4 = 30.0
mean_ignoring_nan = np.nanmean(data_with_nan)
print(f”nanmean() での平均 (NaNを無視): {mean_ignoring_nan}”) # 30.0
nanmean()もaxis引数などをサポートしています
data_with_nan_2d = np.array([[10, 20, np.nan],
[40, np.nan, 60]])
print(f”\nNaNを含む2次元データ:\n {data_with_nan_2d}”)
axis=0 で nanmean を計算
nanmean_axis0 = np.nanmean(data_with_nan_2d, axis=0)
print(f”axis=0 での nanmean:\n {nanmean_axis0}”)
結果[0]: np.nanmean([10, 40]) = 25.0
結果[1]: np.nanmean([20, nan]) = 20.0
結果[2]: np.nanmean([nan, 60]) = 60.0
結果: [25. 20. 60.]
“`
NaNを含むデータに対して平均を計算する場合は、np.nanmean()
を使うのが一般的です。
空の配列の平均
要素が一つもない空の配列に対してmean()
メソッドを呼び出すと、RuntimeWarning
が発生し、結果としてNaN
が返されます。これは、「0で割る」操作(合計が0で要素数が0)が発生するためです。
“`python
import numpy as np
empty_arr = np.array([])
空の配列の平均
mean_empty = empty_arr.mean()
print(f”空の配列の平均: {mean_empty}”) # nan
“`
空の配列が入力される可能性がある場合は、事前に配列が空でないかチェックするか、結果がNaNになることを想定しておく必要があります。
次元や形状の不一致 (axis指定ミスなど)
axis
引数で存在しない軸を指定したり、out
引数で指定した配列の形状やデータ型が結果と一致しない場合、エラーが発生します。
“`python
import numpy as np
arr2d = np.array([[1, 2], [3, 4]]) # shape (2, 2)
存在しない軸を指定 -> AxisError
try:
arr2d.mean(axis=2) # 軸0, 軸1 は存在するが、軸2 は存在しない
except np.AxisError as e:
print(f”\nAxisError 例外: {e}”)
out引数で形状が合わない配列を指定 -> ValueError
out_arr = np.zeros(3) # shape (3,) だが、axis=0の計算結果は shape (2,)
try:
arr2d.mean(axis=0, out=out_arr)
except ValueError as e:
print(f”ValueError 例外: {e}”)
“`
これらのエラーは、NumPyの標準的なエラーハンドリングによって検知されます。発生した場合は、元の配列の形状を確認し、axis
やout
引数の指定が正しいか見直しましょう。
まとめ
本記事では、NumPy配列の平均計算を効率的かつ柔軟に行うための中心的なツールであるmean()
メソッドについて、基本的な使い方から詳細な応用までを網羅的に解説しました。
NumPyのmean()
メソッドは:
- Python標準機能に比べて格段に高速でメモリ効率が良いです。
- 配列全体の平均を簡単に計算できます (
arr.mean()
またはnp.mean(arr)
)。 - 多次元配列の特定の軸(行や列など)に沿った平均計算を
axis
引数で指定できます。これはNumPyの最も強力な機能の一つです。 - 計算に使用する、あるいは結果として得られるデータ型を
dtype
引数で制御できます(通常はデフォルトの浮動小数点型で十分安全です)。 - 計算結果をあらかじめ用意した配列に格納することで、メモリ管理を最適化できる
out
引数があります。 - 計算結果の次元数を元の配列と同じに保つことができる
keepdims
引数があり、ブロードキャストを利用した演算などで非常に便利です。 - NaN(非数)を含むデータに対しては、NaNを無視して平均を計算する
np.nanmean()
という関連関数があります。
これらの機能を理解し使いこなすことで、データ分析、統計処理、科学技術計算など、NumPyを扱う様々な場面で配列の平均計算を効率的に、そして意図通りに行うことができるようになります。
平均値は、データセットの最も基本的な統計量の一つです。NumPyのmean()
メソッドは、この重要な計算をNumPyの強力な配列処理能力を最大限に活かして実現します。ぜひ本記事で学んだ内容を参考に、あなたのNumPy配列操作にmean()
メソッドを積極的に活用してください。
平均計算だけでなく、NumPyには合計(sum()
)、最小値(min()
)、最大値(max()
)、標準偏差(std()
)、分散(var()
)など、同様にaxis
や他の引数をサポートする多くのメソッドや関数が用意されています。mean()
メソッドの使い方をマスターすれば、これらの関連関数も容易に使いこなせるようになるでしょう。
データから価値を引き出すための第一歩として、NumPyのmean()
をあなたのツールキットに加え、今すぐ活用を始めてください!