Numpy数组切片转换内部数据

时间:2015-05-29 17:17:23

标签: python c arrays numpy slice

我正在写一个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 

可以很容易地看出,aaSlicing是python的相同数组。但是,读取数据的C函数将数据视为转置的类型。 C认为aSliced好像是

a.T.reshape((10,6))

有谁知道为什么会出现此错误以及如何正确规避错误?当然,在C代码中进行转置很容易。但是,我希望我的程序能够处理这两种类型的数组。

我希望在我的C扩展中有一个解决方案,即我的扩展名的用户不必关心他们的输入是否是&#34;切片&#34;或不。不过,我尝试将aSliced的深层副本放入我的扩展程序中 - 这与aSliced的错误结果相同。

我正在使用python 3.4 64bit,numpy 1.9.1,Win8 64bit和Visual Studio 10 64bit C编译器。

1 个答案:

答案 0 :(得分:0)

正如hpaulj指出的那样,可以使用标志F_CONTIGUOUS找出内存结构。我花了很多时间试图从C中找到一种方法来读取这个标志。据我所知,可以通过评估trials_array->flags % 2的值来完成。但是,我没有找到任何有关此问题的明确表述的参考文献。

trials_array->flags是整数。 numpy标志常量NPY_C_CONTIGUOUSNPY_F_CONTIGUOUS等是两个幂的整数。如果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的示例。