我正在编写一个 C 扩展来处理 numpy 数组。我写了一个函数来读取和输出 numpy 数组。使用它时,我注意到在输入数组中使用切片时会出现一种奇怪的行为。
读取(boolan)数组的 C 函数:
char **pymatrix_to_CarrayptrsChar(PyArrayObject *arrayin) {
char **result, *array;
int i, n, m, j;
n = arrayin->dimensions[0];
m = arrayin->dimensions[1];
result = ptrvectorChar(n, m);
array = (char *) arrayin->data; /* pointer to arrayin data as int */
for (i = 0; i < n; i++) {
result[i] = &array[i * m];
}
printArrChar(result, n, m);
return result;
}
ptrvectorChar
是内存分配函数:
char **ptrvectorChar(long dim1) {
char **v;
if (!(v = malloc(dim1 * sizeof(char*)))) {
PyErr_SetString(PyExc_MemoryError,
"In **ptrvectorChar. Allocation of memory for character array failed.");
exit(0);
}
return v;
}
打印完成:
void printArrChar(char **arr, int dim1, int dim2) {
int i, j;
for (i = 0; i < dim1; i++) {
for (j = 0; j < dim2; j++) {
printf("%i ", arr[i][j]);
}
printf("\n");
}
}
我用于重现错误的 python 脚本是:
import numpy as np
import MyExtension
np.random.seed(1)
x = np.array((1,1,1,1,1,1)).astype(bool)
a = np.round(np.random.rand(trialNr, lakeNr)).astype(bool)
aSlicing = a[:, x]
print("a:")
print(a + 0)
print("aSlicing:")
print(aSlicing + 0)
print("C output for a:")
MyExtension.MyFunction(a)
print("C output for aSlicing:")
MyExtension.MyFunction(aSlicing)
输出是:
a:
[[0 1 0 0 0 0]
[0 0 0 1 0 1]
[0 1 0 1 0 1]
[0 0 1 1 0 1]
[1 1 0 0 0 1]
[0 0 1 1 1 0]
[1 1 0 1 1 1]
[0 1 0 0 1 0]
[0 0 0 1 0 0]
[0 0 1 0 1 1]]
aSlicing:
[[0 1 0 0 0 0]
[0 0 0 1 0 1]
[0 1 0 1 0 1]
[0 0 1 1 0 1]
[1 1 0 0 0 1]
[0 0 1 1 1 0]
[1 1 0 1 1 1]
[0 1 0 0 1 0]
[0 0 0 1 0 0]
[0 0 1 0 1 1]]
C output for a:
0 1 0 0 0 0
0 0 0 1 0 1
0 1 0 1 0 1
0 0 1 1 0 1
1 1 0 0 0 1
0 0 1 1 1 0
1 1 0 1 1 1
0 1 0 0 1 0
0 0 0 1 0 0
0 0 1 0 1 1
C output for aSlicing:
0 0 0 0 1 0
1 0 0 0 1 0
1 0 1 0 1 1
0 0 0 0 0 1
0 1 0 0 0 1
0 1 1 1 0 1
1 0 1 0 0 0
0 0 0 1 1 1
0 1 0 1 1 1
1 0 1 0 0 1
很容易看出,a
和aSlicing
对于python来说是相同的数组。但是,读取数据的 C 函数将数据视为某种转置。 C 将 aSliced 视为
a.T.reshape((10,6))
有谁知道为什么会出现这个错误以及如何正确规避它?当然,在 C 代码中转置很容易。但是,我希望我的程序能够处理这两种类型的数组。
我更喜欢我的 C 扩展中的解决方案,即我的扩展的用户不必关心他们的输入是否被“切片”。尽管如此,我还是尝试将 aSliced
的深拷贝放入我的扩展中 - 这与 aSliced
的结果相同。
我正在使用 python 3.4 64 位、numpy 1.9.1、Win8 64 位和 Visual Studio 10 64 位 C 编译器。
最佳答案
正如 hpaulj 所指出的,可以使用标志 F_CONTIGUOUS
找出内存结构。我花了很多时间试图找到一种从 C 中读取此标志的方法。据我所知,可以通过评估 trials_array->flags % 2
的值来完成。但是,我没有找到任何对这个问题有明确解释的引用资料。
trials_array->flags
是一个整数。 numpy 标志常量 NPY_C_CONTIGUOUS
、NPY_F_CONTIGUOUS
等是整数,是 2 的幂。如果 trials_array->flags
的二进制表示中的相应位置为 1,则似乎设置了标志。
即使知道内存结构,读取数组也不像我想的那么简单。我找到了一种更容易的方法将 numpy 数组转换为 C 数组:使用
char *myArray;
PyArrayObject *myArray_Numpy;
PyArray_AsCArray(&myArray_Numpy, (void *) &myArray, myArray_Numpy->dimensions, 2, PyArray_DescrFromType(NPY_BOOL));
//Do something with the array
PyArray_Free(myArray_Numpy, myArray);
我找到了一个使用这些函数的例子 here .
关于python - Numpy数组切片转置内部数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30535467/