NumPyでは配列の指定の軸方向の要素の中の最小値を取得する方法として、numpy.amin()とndarray.min()が用意されています。
なお、numpy.amin()とndarray.min()は、引数の書き方や使い方は全く同じです。しかし、前者は関数なので配列を引数に渡します。後者はメソッドなので配列は前に書きます。
これらについてサンプルコードとともに、詳しく解説していきます。
目次
1. numpy.amin()とndarray.min()の使い方
まずは、numpy.amin()と、ndarray.min()のそれぞれの書き方とオプション引数を確認しておきましょう。
numpy.amin()の書き方:
numpy.amin(a, axis=None, out=None, keepdims=<no value>, initial=<no value>)
パラメーター:
引数 | 型 | 解説 |
a | array_like | 配列を渡します。 |
axis(optional) | None or int or tuple of ints | どの軸を基準に最小値を求めるかを指定します。デフォルト(None)では配列全体の要素の中の最大値を1つだけ取得します。もし、複数の軸をタプルで渡すと、指定の全ての軸の中での最小値を返します。 |
out(optional) | ndarray | ここで指定した配列を、関数の戻り値で上書きします。アウトプット先に指定する配列のshapeと、関数の戻り値のshapeは一致している必要があります。 |
keepdims(optional) | bool | これをTrueに指定すると、元の配列の次元数を維持します。指定したaxisは1になります。例えば、shape(2, 3, 4)の3次元配列の場合、axis=0ではshape(1, 3, 4)、axis=1ではshape(2, 1, 4)、axis=2ではshape(2, 3, 1)になります。 |
initial(optional) | scalar | 関数で生成する配列の要素の最大値を指定します。 |
戻り値:
ndarray:配列aの最小値を求めます。axis=Noneの時は、スカラーが生成されます。axisを指定した時は、生成される配列は、元の配列の次元数-1になります。 |
一緒に確認したい関数:
ndarray.min()の書き方:
ndarray.min(axis=None, out=None, keepdims=<no value>, initial=<no value>)
上述の通りnumpy.amin()も、ndarray.min()も機能は全く同じです。前者が関数で、後者がメソッドであるため、最小値を求めたい配列を引数に渡すのか、前に書くのかだけが異なります。
そのため、ここからはnumpy.amin()を例に解説を進めていきます。
1.1. 配列内の最小の要素を返す
numpy.amin()に配列を渡すと、その配列内の要素の最小値を返します。
以下の配列を例に見てみましょう。
import numpy as np
arr = np.random.randint(0, 10, 10)
arr
これをnumpy.amin()に渡すと、最小値である1を返します。
''' 最小値を返す '''
np.amin(arr)
多次元配列の場合も同様に、その配列内の全要素のうちの最小値を返します。
以下のコードは2次元配列の場合ですが、3次元配列以上でも全く同じです。
''' 多次元配列の場合も最小値を返す '''
# 2次元配列を生成
arr = np.random.randint(0, 10, (3, 5))
print('arr:\n', arr)
min = np.amin(arr)
print('最小値: \n', min)
注: 配列内に欠損値NaNがある場合 – numpy.nanmin()
なお、numpy.amin()に、欠損値NaNがある配列を渡すと、それを最小値として返します。
''' 配列の中に欠損値のNanがある場合 '''
# 値の1つを欠損値にした配列を生成
arr = np.random.randint(0, 10, 10).astype(float)
arr[2] = np.NaN
print(arr)
# np.amin()を実行すると欠損値が最小値になる
min = np.amin(arr)
print(min)
これを避けたい場合は、numpy.nanmin()を使います。
''' 欠損値を含めたくない場合は、numpy.nanmin()を使う '''
np.nanmin(arr)
なお、numpy.nanmin()は、numpy.amin()と書き方は全く同じです。
1.2. 多次元配列の指定の軸方向の要素の最小値を返す(axis)
多次元配列の場合、オプション引数のaxisを指定することで、指定の軸方向の要素のうちの最小値を返します。
以下は2次元配列の場合です。2次元配列ではaxis=0は行でaxis=1は列です。そのため、axis=0を指定すると行方向の要素のうちの最小値を返します。一方で、axis=1を指定すると列方向の要素のうちの最小値を返します。
この時の戻り値のshapeは、元の配列のshapeから指定の軸を取り除いたものになります。例えば、元の2次元配列がshape(N, M)としたら、axis=0の場合はshape(M,)に、axis=1の場合はshape(N,)になります。
以下のコードでご確認ください。
''' 多次元配列でオプション引数axisを指定 '''
# 2次元配列を生成
arr = np.random.randint(1, 10, (3, 4))
print('arr:\n', arr)
# axis=0で行方向の最小値
min0 = np.amin(arr, axis=0)
print('axis=0:\n', min0)
# axis=1で列方向の最小値
min1 = np.amin(arr, axis=1)
print('axi=1:\n', min1)
3次元配列の場合も見てみましょう。
3次元配列ではaxis=0は奥行き方向、axis=1は行方向、axis=2は列方向です。それぞれ指定の方向に沿った要素のうちの最小値を返ます。
3次元配列を渡した場合の戻り値のshapeは、元の3次元配列がshape(N, M, O)としたら、axis=0の場合はshape(M, O)に、axis=1の場合はshape(N, O)に、axis=2の場合はshape(N, M)になります。
''' 3次元配列でオプション引数axisを指定 '''
# 2次元配列を生成
arr = np.random.randint(1, 10, (3, 2, 4))
print('arr:\n', arr, '\n')
# axis=0で奥行き方向の最小値
min0 = np.amin(arr, axis=0)
print('axis=0:\n', min0)
# axis=1で行方向の最小値
min1 = np.amin(arr, axis=1)
print('axi=1:\n', min1)
# axis=2で列方向の最小値
min2 = np.amin(arr, axis=2)
print('axi=2:\n', min2)
注: numpy.minimum()を使うべきケース
なお、多次元配列で最初の軸が2(arr.shape[0]=2)の場合、つまり2次元配列なら行数が2、3次元配列なら奥行き数が2の場合で、最初の軸の要素のうち、値が小さな方を取得する時は、numpy.amin()よりもnumpy.minimum()の方が高速です。
以下のコードをご覧ください。
import numpy as np
''' 多次元配列で、arr.shape[0]=2の場合はminimum()の方が高速 '''
# a.shape[0]=2の2次元配列を生成
arr = np.random.randint(1, 10, (2, 5))
print('arr:\n', arr)
print('shape[0]:\n', arr.shape[0], '\n')
# numpy.amin()
amin = np.amin(arr, axis=0)
print('amin:\n', amin)
# numpy.minimum()
mini = np.minimum(arr[0], arr[1])
print('mini:\n', mini)
このコードでは、numpy.amin(arr, axis=0)とnumpy.minimum(arr[0], arr[1])の戻り値は同じですが、後者の方がずっと高速です。
実際に処理時間を計測してみましょう。
まず、np.amin(arr, axis=0)では1回の処理に3.62マイクロ秒かかっています。
%%timeit
np.amin(arr, axis=0)
次に、np.minimum(arr[0], arr[1])では771ナノ秒かかっています。
%%timeit
np.minimum(arr[0], arr[1])
このように、両者の間には5倍近い速度差があります。
そのため、arr.shape[0]=2 の場合で、axis=0の軸方向の要素の最大値を取得したい場合は、numpy.amin()ではなく、numpy.minimum()を使いましょう。
1.3. 戻り値の最大値を指定(initial)
オプション引数のinitialを使うと指定した値が戻り値の最大値になります。実際の配列内に、これで指定した値よりも小さな値がない場合は、指定した値を返します。
以下のコードでご確認ください。
''' オプション引数initialで戻り値の最大値を指定 '''
# 配列を生成
arr = np.array([10, 20, 30, 40, 50])
print(arr)
# initial=5を指定
min = np.min(arr, initial=5)
print(min)
注: numpy.amin()のinitalとPython組み込み関数min()のdefaultの違い
numpy.amin()と、Pythonの組み込み関数min()で混同されやすい点があるので念の為解説しておきます。
Pythonの組み込み関数のmin()のオプション引数defaultは、関数に渡した配列の要素が空の時に返す値です。一方で、numpy.amin()は、配列の中にitinialで指定した値より小さな値がない場合に、指定の値を返します。
以下のコードで確認しておきましょう。
''' numpy.min()とPython組み込みのmin()の違い'''
print(np.min([6], initial=5))
print(min([6], default=5))
1.4. 元の配列の次元数を維持(keepdims)
オプション引数keepdims=Trueを指定すると、戻り値の配列の次元数が、元の配列のものを維持します。この時、指定したaxisの要素数は1になります。
例えば、shape(N, M)の2次元配列の場合、keepdims=Trueを指定すると、戻り値の配列は、axis=0の場合はshape(1, M)、axis=1の場合はshape(N, 1)になります。
以下のコードでご確認ください。
''' オプション引数keepdims=Trueの場合① '''
# 2次元配列を生成
arr = np.random.randint(1, 10, (3, 4))
print('arr:\n', arr)
print('shape:', arr.shape, '\n')
# axis=0
out0 = np.amin(arr, axis=0, keepdims=True)
print('out0(axis=0):\n', out0)
print('shape:', out0.shape, '\n')
# axis=1
out1 = np.amin(arr, axis=1, keepdims=True)
print('out1(axis=1):\n', out1)
print('shape:', out1.shape)
3次元配列の場合も見てみましょう。
この場合、shape(N, M, O)としたら戻り値の配列は、axis=0の場合はshape(1, M, O)、axis=1の場合はshape(N, 1, O)、axis=2の場合はshape(N, M, 1)になります。
以下のコードでご確認ください。
''' オプション引数keepdims=Trueの場合② '''
# 3次元配列を生成
arr = np.random.randint(1, 10, (3, 4, 5))
print('arr:\n', arr)
print('shape:', arr.shape, '\n')
# axis=0
out0 = np.amin(arr, axis=0, keepdims=True)
print('out0(axis=0):\n', out0)
print('shape:', out0.shape, '\n')
# axis=1
out1 = np.amin(arr, axis=1, keepdims=True)
print('out1(axis=1):\n', out1)
print('shape:', out1.shape, '\n')
# axis=2
out2 = np.amin(arr, axis=2, keepdims=True)
print('out1(axis=2):\n', out2)
print('shape:', out2.shape)
1.5. 戻り値の配列で既存の配列を上書き(out)
オプション引数outは、指定した配列を、numpy.amin()の戻り値の配列で上書きしたい時に使います。
アウトプット先の配列と、戻り値の配列はshapeが一致している必要があります。もしshapeが揃っていなければエラーになります。そして、アウトプット後の配列のデータ型はアウトプット先の配列と同じものになります。
以下のコードで確認しましょう。
''' オプション引数outでアウトプット(上書き)する配列を指定 '''
# 2次元配列を生成
arr = np.random.randint(1, 10, (3, 5))
print('arr:\n', arr, '\n')
# アウトプット先の配列を生成
a_out = np.zeros(5)
print('a_out(関数実行前):\n', a_out, '\n')
# numpy.amin()のアウトプット先をa_outに指定
np.amin(arr, axis=0, out=a_out)
print('a_out(関数実行後):\n', a_out)
2. まとめ
以上が、numpy.amin()とndarray.min()の使い方です。
ndarray.min()は、numpy.amin()と配列を書く位置が異なるだけで全く同じですが、念のためサンプルコードを貼っておきます。
import numpy as np
arr1 = np.arange(6).reshape(2, 3)
# メソッドなので、配列を前に書きます。
print(arr1.min())
# axisの指定
print(arr1.min(axis=1))
# keepdimsの指定
print(arr1.min(keepdims=True))
# initialの指定
print(arr1.min(initial=-100))
# outの指定
a_out = np.zeros(2)
arr1.min(axis=1, out=a_out)
print(a_out)
それでは最後に、numpy.amin()とndarray.min()の重要ポイントをまとめておきましょう。
- 指定の配列の指定の軸方向の要素のうち最大値を返す。
- NaNと実数との比較ではNaNを最大値として返す。
- NaNと実数との比較で実数を返して欲しい場合はnumpy.nanmin()を使う。
- 多次元配列でオプション引数axisを指定する場合、その戻り値のshapeは元の配列のshapeから指定の軸を取り除いたものになる。
- 多次元配列で最初の軸(shape[0])が2の時、最初の軸(axis=0)の最大値の要素を取得したい場合はnumpy.minimum(arr[0], arr[1])を使う。
- オプション引数で「keepdims=True」を指定した場合、戻り値は、指定のaxisを1にしたものになる。
- オプション引数initialを指定した場合、戻り値の配列の要素の最小値が指定の数値になる(Python組み込み関数max()のオプション引数defaultとの違いに注意すること)。
- オプション引数outで、アウトプット先の配列を指定する場合、戻り値とアウトプット先の配列のshapeが一致している必要がある。
また、書き方はnumpy.amin()と全く同じで、最小値ではなく最大値を返す関数に、numpy.amax()があります。これについては、『numpy.amax, ndarray.max – 配列の指定の軸の要素の最大値を取得』で解説しています。
そして、NumPyの配列で最小値を取得することができる関数やメソッドには、他にも、
- numpy.argmin: 最小値のインデックスを返す。
- numpy.minimum: 2つの配列の最小値を返す。
これらは、それぞれ、『numpy.argmin, ndarray.argmin – 最小値のインデックスを取得』と、『numpy.minimum – 2つの配列の各要素の最小値を取得』で解説していますので、ぜひ参考にしてください。
コメントを残す