NumPy C-API: `PyObject *PyArray_Where()` の詳細解説とサンプルコード


PyArray_Where() 関数は、条件を満たす要素の位置を PyArrayObject で返します。これは、条件に基づいてマスクを作成したり、特定の条件を満たす要素を抽出したりする際に役立ちます。

引数

  • c
    条件を満たす要素に割り当てる値を含む PyArrayObject またはスカラー値です。
  • b
    比較対象となる PyArrayObject またはスカラー値です。
  • a
    条件を評価する PyArrayObject です。

戻り値

条件を満たす要素の位置を含む PyArrayObject です。

詳細

PyArray_Where() は、a, b, c の各要素を比較し、次の条件を満たす要素の位置を PyArrayObject に格納します。

  • a[i] <= b[i]
  • a[i] >= b[i]
  • a[i] < b[i]
  • a[i] > b[i]
  • a[i] != b[i]
  • a[i] == b[i]

比較演算子は、PyArray_Descrtypecode に基づいて決定されます。

c 引数は、条件を満たす要素に割り当てる値を指定します。cNULL の場合、デフォルト値が使用されます。デフォルト値は、abdtype によって異なります。


#include <numpy/ndarray.h>

int main() {
  PyArrayObject *a = PyArray_Zeros(2, NPY_INT32);
  PyArrayObject *b = PyArray_Ones(2, NPY_INT32);
  PyArrayObject *c = PyArray_Where(a, b, NULL);

  // c[0] は 1, c[1] は 0
  printf("%d %d\n", PyArray_GETITEM(c, 0), PyArray_GETITEM(c, 1));

  Py_DECREF(a);
  Py_DECREF(b);
  Py_DECREF(c);

  return 0;
}
  • PyArray_Where() は、メモリを割り当てるため、使用後は Py_DECREF() で解放する必要があります。
  • a, b, c はすべて同じ dtype でなければなりません。
  • 条件を満たす要素がない場合は、空の PyArrayObject が返されます。
  • PyArray_Where() は、条件を満たす要素の位置のみを返します。要素の値自体は返されません。


コード

#include <numpy/ndarray.h>

int main() {
  npy_intp dims[] = {2};
  PyArrayObject *a = PyArray_Zeros(2, NPY_INT32);
  PyArrayObject *b = PyArray_Ones(2, NPY_INT32);
  PyArrayObject *c = PyArray_Where(a, b, NULL);

  // 条件を満たす要素のインデックスを出力
  for (int i = 0; i < PyArray_Size(c); i++) {
    printf("%d ", PyArray_GETITEM(c, i));
  }

  printf("\n");

  // 条件を満たす要素の値を出力
  for (int i = 0; i < PyArray_Size(a); i++) {
    if (PyArray_GETITEM(c, i)) {
      printf("%d ", PyArray_GETITEM(a, i));
    }
  }

  printf("\n");

  Py_DECREF(a);
  Py_DECREF(b);
  Py_DECREF(c);

  return 0;
}
  1. npy_intp dims[] = {2}; 行は、2要素の配列を作成するための次元情報を定義します。
  2. PyArray_Zeros()PyArray_Ones() 関数は、それぞれすべての要素が 0 または 1 で初期化された PyArrayObject を作成します。
  3. PyArray_Where() 関数は、ab を比較し、条件を満たす要素の位置を c に格納します。
  4. for ループは、c の各要素を反復し、条件を満たす要素のインデックスを出力します。
  5. 2番目の for ループは、a の各要素を反復し、条件を満たす要素の値を出力します。
  6. 最後に、作成したすべての PyArrayObject を解放します。
  • マスクされた配列を作成する
  • 多次元配列を使用する
  • 条件を満たす要素に対してカスタム処理を実行する
  • 異なる比較演算子を使用する


NumPy の where() 関数

where() 関数は、条件に基づいて配列の要素を置き換えるために使用できます。これは、PyArray_Where() と似ていますが、PyArrayObject を返す代わりに、入力配列を直接変更します。

import numpy as np

a = np.array([1, 2, 3, 4, 5])
b = np.array([True, False, False, True, True])
c = np.where(b, a, 0)

print(c)  # 出力: [1 0 0 4 5]

リスト内包表記

リスト内包表記は、条件に基づいて新しいリストを作成するために使用できます。これは、PyArray_Where() よりも簡潔で読みやすいコードになる場合があります。

import numpy as np

a = np.array([1, 2, 3, 4, 5])
b = np.array([True, False, False, True, True])
c = [a[i] for i in range(len(a)) if b[i]]

print(c)  # 出力: [1 4 5]

broadcasting

ブロードキャストは、異なる形状の配列を同じ形状に拡張するために使用できます。これは、条件に基づいてマスクを作成するために使用できます。

import numpy as np

a = np.array([1, 2, 3, 4, 5])
b = np.array([True, False, False, True, True])
c = a * b

print(c)  # 出力: [1 0 0 4 5]

関数

条件を満たす要素を抽出するために、独自の関数を作成することもできます。これは、複雑な条件やカスタム処理が必要な場合に役立ちます。

import numpy as np

def filter_array(a, b):
  result = []
  for i in range(len(a)):
    if b[i]:
      result.append(a[i])
  return result

a = np.array([1, 2, 3, 4, 5])
b = np.array([True, False, False, True, True])
c = filter_array(a, b)

print(c)  # 出力: [1 4 5]

どの方法を選択するべきか?

最適な方法は、特定の状況によって異なります。

  • 複雑な条件やカスタム処理が必要な場合は、ブロードキャストまたは独自の関数を使用します。
  • コードが読みやすく簡潔であることが重要であれば、リスト内包表記を使用します。
  • シンプルで効率的な方法が必要な場合は、PyArray_Where() または where() 関数を使用します。
  • メモリ使用量も考慮する必要があります。リスト内包表記は、他の方法よりも多くのメモリを使用する場合があります。
  • どの方法を選択する場合でも、パフォーマンスを考慮する必要があります。PyArray_Where() は、他の方法よりも高速である場合があります。