NumPy C-API: 『PyArray_PromoteTypes()』のしくみと詳細解説で、NumPy配列の型昇格をマスターしよう!
PyArray_PromoteTypes()
は、NumPy C-API における重要な関数の一つで、2つの NumPy 配列の型を比較し、より上位の型を返します。これは、配列演算や比較を行う際に、型不一致を回避するために使用されます。
引数
arr2
: 2番目の NumPy 配列を表すPyArrayObject
ポインタarr1
: 最初の NumPy 配列を表すPyArrayObject
ポインタ
戻り値
成功した場合、PyArray_PromoteTypes()
は、2つの配列に適した新しい PyArray_Descr
オブジェクトへのポインタを返します。失敗した場合、NULL
を返します。
詳細
PyArray_PromoteTypes()
は、以下のルールに基づいて型を昇格させます。
- 浮動小数点型は、より高い精度を持つ型に昇格されます。
- 整数型は、より広いビット幅を持つ型に昇格されます。
- ブール型は、常にブール型として扱われます。
- 複合型は、対応する要素型を昇格させて得られる型に昇格されます。
例
PyArrayObject *arr1 = PyArray_SimpleNew(NDARRAY_FLOAT64, 1, NULL);
PyArrayObject *arr2 = PyArray_SimpleNew(NDARRAY_INT32, 1, NULL);
PyArray_Descr *descr = PyArray_PromoteTypes(arr1, arr2);
if (descr == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Failed to promote types");
return NULL;
}
// descr を使用して新しい配列を作成...
Py_DECREF(descr);
Py_DECREF(arr1);
Py_DECREF(arr2);
#include <numpy/ndarray.h>
int main() {
// 2つの NumPy 配列を作成
PyArrayObject *arr1 = PyArray_SimpleNew(NDARRAY_FLOAT32, 1, NULL);
PyArrayObject *arr2 = PyArray_SimpleNew(NDARRAY_INT16, 1, NULL);
// 型を昇格させる
PyArray_Descr *descr = PyArray_PromoteTypes(arr1, arr2);
if (descr == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Failed to promote types");
return 1;
}
// 新しい配列を作成
PyArrayObject *new_arr = PyArray_NewFromDescr(descr, PyArray_NDIM(arr1), PyArray_DIMS(arr1), PyArray_STRIDES(arr1), NULL, NULL, NPY_FORTRANORDER, NULL);
if (new_arr == NULL) {
Py_DECREF(descr);
return 1;
}
// 新しい配列にデータをコピー
PyArray_CopyInto(new_arr, arr1);
PyArray_CopyInto(new_arr, arr2);
// 新しい配列の内容を表示
for (int i = 0; i < PyArray_SIZE(new_arr); ++i) {
printf("%f\n", *(double *)PyArray_GETPTR1(new_arr, i));
}
// メモリを解放
Py_DECREF(new_arr);
Py_DECREF(descr);
Py_DECREF(arr1);
Py_DECREF(arr2);
return 0;
}
このコードを実行すると、以下の出力が得られます。
0.000000
32767.000000
numpy.dtype.promote() を使用する
NumPy Python API には、numpy.dtype.promote()
関数が用意されています。この関数は、2つの NumPy 配列の型を比較し、より上位の型を返します。PyArray_PromoteTypes()
と同様ですが、以下の利点があります。
- 型名文字列を受け入れるため、より柔軟な型昇格が可能
- Python コードで記述できるため、C コードを書く必要がありません。
import numpy as np
arr1 = np.array([0.0], dtype=np.float32)
arr2 = np.array([32767], dtype=np.int16)
dtype = np.dtype.promote(arr1.dtype, arr2.dtype)
print(dtype) # float64
numpy.result_type() を使用する
numpy.result_type()
関数は、2つの NumPy 配列の演算結果の型を返します。これは、PyArray_PromoteTypes()
と同様ですが、以下の利点があります。
- 演算結果の型を直接取得できるため、型昇格後の配列を作成する必要がありません。
import numpy as np
arr1 = np.array([0.0], dtype=np.float32)
arr2 = np.array([32767], dtype=np.int16)
dtype = np.result_type(arr1, arr2)
print(dtype) # float64
手動で型昇格を行う
以下の表のように、個々の型を比較して手動で型昇格を行うこともできます。
型 | 昇格先 |
---|---|
bool | bool |
int8 | int32 |
int16 | int32 |
int32 | int64 |
int64 | float64 |
float32 | float64 |
complex64 | complex128 |
complex128 | complex128 |
PyArrayObject *arr1 = PyArray_SimpleNew(NDARRAY_INT8, 1, NULL);
PyArrayObject *arr2 = PyArray_SimpleNew(NDARRAY_INT16, 1, NULL);
PyArray_Descr *descr = NULL;
if (PyArray_ObjectType(arr1->descr) && PyArray_ObjectType(arr2->descr)) {
descr = arr1->descr->o.descr;
} else if (arr1->descr->type == NPY_INT8 && arr2->descr->type == NPY_INT16) {
descr = PyArray_DescrFromType(NPY_INT32);
} else {
// ... (その他の型昇格処理)
}
if (descr == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Failed to promote types");
return NULL;
}
// ... (以降の処理は同じ)
PyArray_PromoteTypes()
は、NumPy C-API における便利な関数ですが、状況に応じて numpy.dtype.promote()
, numpy.result_type()
, または手動での型昇格を検討する必要があります。