NumPy C-API の enum NPY_SELECTKIND を駆使して、高速かつ効率的な要素抽出を実現
主な値とその意味
- NPY_SELECT_RANDOM
ランダムな順序で要素を選択します。 - NPY_SELECT_BACKWARDS
逆順に要素を選択します。 - NPY_SELECT_NEAREST
最も近いメモリ位置に格納されている要素を選択します。 - NPY_SELECT_STANDARD
標準的なメモリ配置で格納されている要素のみを選択します。 - NPY_SELECT_CONTIGUOUS
隣接するメモリ位置に格納されている要素のみを選択します。
使用例
#include <numpy/ndarrayobject.h>
npy_intp indices[10];
npy_intp strides[2] = {1, 2};
// 隣接するメモリ位置に格納されている要素のみ抽出
NPY_SELECT_KIND(NPY_SELECT_CONTIGUOUS, indices, 10, strides, 2, array);
// 標準的なメモリ配置で格納されている要素のみ抽出
NPY_SELECT_KIND(NPY_SELECT_STANDARD, indices, 10, strides, 2, array);
// 最も近いメモリ位置に格納されている要素のみ抽出
NPY_SELECT_KIND(NPY_SELECT_NEAREST, indices, 10, strides, 2, array);
// 逆順に要素を選択
NPY_SELECT_KIND(NPY_SELECT_BACKWARDS, indices, 10, strides, 2, array);
// ランダムな順序で要素を選択
NPY_SELECT_KIND(NPY_SELECT_RANDOM, indices, 10, strides, 2, array);
NPY_SELECT_BACKWARDS
とNPY_SELECT_RANDOM
は、要素の抽出順序を制御するために使用できます。NPY_SELECT_NEAREST
は、配列が断片化されている場合に役立ちます。NPY_SELECT_CONTIGUOUS
とNPY_SELECT_STANDARD
は、配列が C 言語の連続メモリに格納されている場合にのみ使用できます。
- NumPy C-API を使用する前に、NumPy のドキュメントをよく読んでください。
- 上記のコードはあくまで例であり、状況に応じて変更する必要があります。
- NumPy C-API は複雑な API であり、習得には時間がかかる場合があります。
- NumPy C-API には、
enum NPY_SELECTKIND
以外にも多くの列挙型と関数があります。
例1:隣接するメモリ位置に格納されている要素のみ抽出
#include <numpy/ndarrayobject.h>
int main() {
// 2 次元の NumPy 配列を作成
npy_intp dims[] = {2, 3};
PyArrayObject *array = PyArray_SimpleNewFromData(NDARRAY_DOUBLE, dims, NULL, NPY_ORDER_C);
// 配列の要素に値を設定
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
((double *)PyArray_GET_ITEM(array, i, j))[0] = i * 3 + j;
}
}
// 隣接するメモリ位置に格納されている要素のみ抽出
npy_intp indices[6];
NPY_SELECT_KIND(NPY_SELECT_CONTIGUOUS, indices, 6, array->strides, array->ndim, array);
// 抽出された要素を出力
for (int i = 0; i < 6; i++) {
printf("%d ", ((double *)PyArray_GET_ITEM(array, indices[i], 0))[0]);
}
printf("\n");
// 配列と PyArray オブジェクトを解放
PyArray_XDECREF(array);
return 0;
}
例2:標準的なメモリ配置で格納されている要素のみ抽出
#include <numpy/ndarrayobject.h>
int main() {
// 2 次元の NumPy 配列を作成
npy_intp dims[] = {2, 3};
PyArrayObject *array = PyArray_SimpleNewFromData(NDARRAY_DOUBLE, dims, NULL, NPY_ORDER_F);
// 配列の要素に値を設定
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
((double *)PyArray_GET_ITEM(array, i, j))[0] = i * 3 + j;
}
}
// 標準的なメモリ配置で格納されている要素のみ抽出
npy_intp indices[6];
NPY_SELECT_KIND(NPY_SELECT_STANDARD, indices, 6, array->strides, array->ndim, array);
// 抽出された要素を出力
for (int i = 0; i < 6; i++) {
printf("%d ", ((double *)PyArray_GET_ITEM(array, indices[i], 0))[0]);
}
printf("\n");
// 配列と PyArray オブジェクトを解放
PyArray_XDECREF(array);
return 0;
}
#include <numpy/ndarrayobject.h>
int main() {
// 2 次元の NumPy 配列を作成
npy_intp dims[] = {2, 3};
PyArrayObject *array = PyArray_SimpleNewFromData(NDARRAY_DOUBLE, dims, NULL, NPY_ORDER_C);
// 配列の要素に値を設定
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
((double *)PyArray_GET_ITEM(array, i, j))[0] = i * 3 + j;
}
}
// 最も近いメモリ位置に格納されている要素のみ抽出
npy_intp indices[6];
NPY_SELECT_KIND(NPY_SELECT_NEAREST, indices, 6, array->strides, array->ndim, array);
// 抽出された要素を出力
for (int i = 0; i < 6; i++) {
printf("%d ", ((double *)PyArray_GET_ITEM(array, indices[i], 0))[0]);
}
printf("\n");
// 配列と PyArray オブジェクトを解放
PyArray_XDECREF(array);
return 0;
}
#include <numpy/ndarrayobject.h>
int main() {
// 2 次元の NumPy 配列を作成
npy_intp dims[] = {2, 3};
PyArrayObject *array = PyArray_SimpleNewFromData(NDARRAY_DOUBLE, dims, NULL, NPY_ORDER_C);
// 配列の要素に値を設定
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
((double *)PyArray_GET_ITEM(array, i, j))[0] = i * 3 + j;
}
}
// 偶数の要素のみ抽出
npy_intp indices[3];
PyArray_SelectFromIndex(indices, 3, array, NULL, NULL, 0, NPY_SELECT_CONTIGUOUS);
// 抽出された要素を出力
for (int i = 0; i < 3; i++) {
printf("%d ", ((double *)PyArray_GET_ITEM(array, indices[i], 0))[0]);
}
printf("\n");
// 配列と PyArray オブジェクトを解放
PyArray_XDECREF(array);
return 0;
}
要素の抽出順序を制御
enum NPY_SELECTKIND
とともに、PyArray_SortIndices
関数を使用して、要素の抽出順序を制御することができます。
#include <numpy/ndarrayobject.h>
int main() {
// 2 次元の NumPy 配列を作成
npy_intp dims[] = {2, 3};
PyArrayObject *array = PyArray_SimpleNewFromData(NDARRAY_DOUBLE, dims, NULL, NPY_ORDER_C);
// 配列の要素に値を設定
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
((double *)PyArray_GET_ITEM(array, i, j))[0] = i * 3 + j;
}
}
// 要素を昇順に抽出
npy_intp indices[6];
NPY_SELECT_KIND(NPY_SELECT_CONTIGUOUS, indices, 6, array->strides, array->ndim, array);
PyArray_SortIndices(indices, 6, array);
// 抽出された要素を出力
for (int i = 0; i < 6; i++) {
printf("%d ", ((double *)PyArray_GET_ITEM(array, indices[i], 0))[0]);
}
printf("\n");
// 配列と PyArray オブジェクトを解放
PyArray_XDECREF(array);
return 0;
}
複数の条件を組み合わせる
enum NPY_SELECTKIND
とともに、PyArray_Where
関数を使用して、複数の条件を組み合わせて要素を抽出することができます。
#include <numpy/ndarrayobject.h>
int main() {
// 2 次元の NumPy 配列を作成
npy_intp dims[] = {2, 3};
PyArrayObject *array = PyArray_SimpleNewFromData(NDARRAY_DOUBLE, dims, NULL, NPY_ORDER_C);
// 配列の要素に値を設定
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
((double *)PyArray_GET_ITEM(array, i, j))[0] = i * 3 + j;
}
}
// 偶数かつ 5 未満の要素のみ抽出
npy_intp indices[2];
PyArray_Where(indices, 2, PyArray_And(NULL, PyArray_Eq(array, 0, NPY_BOOL), PyArray_Less(array, 5, NPY_BOOL)), NULL, NULL);
// 抽出された要素を出力
for (int