numpy.where()
numpy.where() は条件文を満たす要素と満たさない要素を、それぞれ指定した数値やブール値に置き換える関数です。
numpy.where(condition, x, y)
condition には配列を含む条件文を渡します。
condition が真である要素は x に置き換えられます。
condition が偽である要素は y に置き換えられます。
numpy.where() を使って、配列の偶数要素を 0, 奇数要素を 1 に置き換えてみます。
# NUMPY_WHERE
# In[1]
import numpy as np
# [[1 2 3]
# [4 5 6]
# [7 8 9]]
a = np.arange(1, 10).reshape(3, 3)
# 偶数を0、奇数を1に置き換える
b = np.where(a % 2 == 0, 0, 1)
print(b)
# [[1 0 1]
# [0 1 0]
# [1 0 1]]
配列要素を直接的に書き換えることによって、b と同じ配列を生成することもできます。
# In[2]
# [[1 2 3]
# [4 5 6]
# [7 8 9]]
c = np.arange(1, 10).reshape(3, 3)
# 条件文
condition = c % 2 == 0
# 条件文を満たす要素を0に書き換える
c[condition] = 0
# 条件文を満たさない要素を1に書き換える
c[~condition] = 1
print(c)
# [[1 0 1]
# [0 1 0]
# [1 0 1]]
一般にはこのような書き方のほうがメモリ効率が良く、処理も高速ですが、numpy.where() は元の配列を変更せずに新しい配列を生成するので、変数の上書きリスクを避けたいときの選択肢となります。
numpy.where() に第 1 引数 (condition) だけ渡すと、条件を満たす要素のインデックス番号を返します。多次元配列に適用した場合、インデックス番号は 1 次元配列の組合わせで表されます。たとえば、In[1] で定義した配列 a の各要素のインデックスは下の図のようになります(赤い数字がインデックス番号)。
偶数になる要素は a[0][1], a[1][0], a[1][2], a[2][2] です。
axis = 0 方向と axis = 1 方向のインデックス番号を 1 次元配列で表すと、それぞれ [0 1 1 2], [1 0 2 1] となります。実際にコードを書いて確認しておきましょう。
# In[3]
# 偶数要素のインデックス番号を取得
d = np.where(a % 2 == 0)
print(d)
# (array([0, 1, 1, 2], dtype=int32), array([1, 0, 2, 1], dtype=int32))
numpy.put()
numpy.put() は指定したインデックスの要素を置き換えます。
この関数は元の配列を変更します。
put(arr, indices, values, mode='raise')
arr には置換対象の配列、indices にはインデックス、values には 置き換える値または配列を渡します。
# NUMPY_PUT
# In[1]
import numpy as np
# [[1 1 1]
# [1 1 1]
# [1 1 1]]
array = np.ones((3, 3), dtype = np.int32)
# 0,2,4,6,8番目の要素を0に置き換える
np.put(array, [0, 2, 4, 6, 8], 0)
print(array)
# [[0 1 0]
# [1 0 1]
# [0 1 0]]
オプション引数 mode は indices で指定したインデックスが arr の範囲外であった場合の戻り値です。デフォルトでは 'raise' となっていて、エラーを返すようになっています。この動作は極めて自然なものですが(そもそも範囲外のインデックスを指定するようなコードを書くべきではないはずです)、希望するなら他の戻り値を選択することもできます。たとえば、mode に 'clip' を指定すると、indices が範囲外であった場合は配列の末尾の要素が置き換えられます。
# In[2]
# [1 1 1 1 1]
array = np.ones(5)
# インデックス10は配列の範囲外なので末尾要素を0に置換
np.put(array, 10, 0, 'clip')
print(array)
# [1. 1. 1. 1. 0.]
numpy.place()
numpy.place() は条件に合う要素を指定した要素で置き換えます。
この関数は元の配列を変更します。
numpy.place(arr, mask, vals)
arr には配列、mask には arr と等しいサイズのブール配列、vals には 1 次元シーケンスを渡します。
# NUMPY_PLACE
# In[1]
import numpy as np
# [[ 1 2 3 4]
# [ 5 6 7 8]
# [ 9 10 11 12]]
array = np.arange(1, 13).reshape(3, 4)
# 偶数(2で割り切れる数)を0に置き換える
np.place(array, array % 2 == 0, 0)
print(array)
# [[ 1 0 3 0]
# [ 5 0 7 0]
# [ 9 0 11 0]]
引数 val にリストなどを指定して複数の要素をまとめて置き換えることもできますが、条件に合わない要素はそのまま据え置かれます(ただ単に条件に合う要素のとなりにあるからといって、巻き込まれて変更されることはありません)。
# In[2]
array = np.array([[1, 2, 3, 4, 1],
[5, 7, 8, 6, 9]])
# 3より大きい要素を[1 0 0]で置き換える
np.place(array, array > 3, [1, 0, 0])
print(array)
# [[1 2 3 1 1]
# [0 0 1 0 0]]
numpy.putmask()
numpy.putmask() は条件に合う要素を指定した値に置き換えます。
この関数は元の配列を変更します。
putmask(a, mask, values)
a には配列に相当するオブジェクト (ndarray や list など)、masik には a と同じサイズのブール配列、values には置き換える値を渡します。
# NUMPY_PUTMASK
# In[1]
import numpy as np
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
array = np.arange(12).reshape(3, 4)
# 5より大きい要素は自身を10倍する
np.putmask(array, array > 5, array*10)
print(array)
# [[ 0 1 2 3]
# [ 4 5 60 70]
# [ 80 90 100 110]]
引数 values に複数の値を渡すこともできます。
# In[2]
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
array = np.arange(12).reshape(3, 4)
# 5より大きい要素は[1 0 0]に置き換える
np.putmask(array, array > 5, [1, 0, 0])
print(array)
# [[0 1 2 3]
# [4 5 1 0]
# [0 1 0 0]]
下記は誤植と思われますので、ご確認ください。
In[3] プログラムの上の説明文で、[ 0 1 1 2]、[ 0 1 1 2] → [0 1 1 2]、[1 0 2 1]
訂正しておきました。
ありがとうございます。m(_ _)m
ChatGPTにnumpy.whereについて質問しました
[Q] NumPyのnp.whereについてやさしく教えてください。
[ChatGPT] NumPyのnp.whereは、条件に基づいて要素を選択するための便利な関数です。条件を満たす要素を選択するための柔軟性と、NumPyの配列操作の一部として使われることがあります。np.whereの基本的な構文は以下の通りです:
np.where(condition, x, y)
conditionは、要素ごとに評価される条件式です。
xは、conditionがTrueの場合に返される値または配列です。
yは、conditionがFalseの場合に返される値または配列です。
np.whereを使用すると、conditionがTrueである要素のインデックスに基づいて、新しい配列または値を作成することができます。以下にいくつかの例を示します:
◆◆◆◆◆
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
new_arr = np.where(arr > 3, arr, 0)
print(new_arr)
# [0 0 0 4 5]
◆◆◆◆◆
arrの要素が3より大きい場合はそのまま、3以下の場合は0となる新しい配列が作成されます。
◆◆◆◆◆
import numpy as np
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([10, 20, 30, 40, 50])
new_arr = np.where(arr1 > 3, arr1, arr2)
print(new_arr)
# [10 20 30 4 5]
◆◆◆◆◆
arr1の要素が3より大きい場合はarr1の要素が選択され、3以下の場合は対応する位置のarr2の要素が選択されます。np.whereは、NumPyの配列操作において非常に便利な関数です。条件に基づいて要素を選択することで、柔軟なデータ処理や要素の置換などの操作が可能になります。
[Q] numpy.where について、ジョークを交えて解説してください。
[ChatGPT] numpy.whereに関するジョークの一つに、「もし彼女がいたら、numpy.whereで探そう」というものがあります。これは、numpy.whereが条件に応じて異なる値を返すことができるため、もし彼女がいたら自分に合った条件を設定してnumpy.whereで探せば、自分にぴったりの彼女を見つけることができるかもしれない、という意味合いです。もちろん、現実的にはnumpy.whereはデータ操作に使われることがほとんどで、彼女探しに使うのはお勧めできません。ただし、numpy.whereを使うことで、自分にぴったりのデータを見つけることはできるかもしれません。