C-numpy:设置固定宽度字符串的数据类型



我正在处理一些在C中表示为字符串的数据。我想根据这些数据返回一个numpy数组。但是,我希望数组具有dtype='SX',其中X是在运行时确定的数字。

到目前为止,我在C中复制数据,如下所示:
    buffer_len_alt = (MAX_WIDTH)*(MAX_NUMBER_OF_ITEMS);
    output_buffer = (char *) calloc(sizeof(char), buffer_len_alt);
    column = PyArray_SimpleNewFromData(1, &buffer_len_alt, NPY_BYTE, output_buffer);
    if (column == NULL){
        return (PyObject *) NULL;
    }
    /* Put strings of length MAX_WIDTH in output_buffer */
    return column;

正如你所看到的,我告诉PyArray_SimpleNewFromData, 'column'是一个1D字节数组,所以当我们称为'column'的指针变成python对象'col'时,我们看到如下:

print(col)
>> array([48,  0,  0, 50, 48, 48, 48,  0,  0, 50, 48, 48, 50, 48, 48, 48,  0, 0], dtype=int8)
print(col.view('S3'))
>> array([b'0', b'200', b'0', b'200', b'200', b'0'], dtype='|S3')

'b'前缀告诉我它们仍然被解释为字节数组,但我想要的是字符串"0","200"等。在本例中,字符串是数字,但并非总是如此。

我知道我可以单独调用b'200'.decode(format)来将每个单独的bytes-object转换为字符串,但是为numpy编写C扩展的全部目的是让所有的循环在C中运行。旧的chararray接口(现在已弃用?)也提供了一个array.decode方法来解码数组中的每个序列,但是由numpy-C接口返回的对象只是普通的ndarray。

我应该传递给SimpleNewFromData而不是NPY_BYTE什么样的typenum,以便python接收具有正确类型信息的数组(例如dtype='S5') ?

或者,如果没有typenum通过SimpleNewFromData实现这一点,那么也许我需要使用SimpleNewFromDescr,但我不知道如何正确设置PyArray_Descr参数,并且文档在这方面确实参差,所以我非常感谢任何形式的指导。

我不熟悉您代码的C部分,但似乎您混淆了字节字符串和unicode字符串的表示。b'200'显示表明您正在Py3中工作,其中unicode是默认的字符串类型。

在Py3会话中:

原始字节:

In [482]: x=np.array([48,  0,  0, 50, 48, 48, 48,  0,  0, 50, 48, 48, 50, 48, 48, 48,  0, 0], dtype=np.int8)

查看一个3字节的字符串。在PY2会话中,b不会被使用。但是视图是一样的

In [483]: x.view('S3')
Out[483]: 
array([b'0', b'200', b'0', b'200', b'200', b'0'], 
      dtype='|S3')

A view不改变数据缓冲区,但astype可以根据需要转换元素,并使用新的数据缓冲区创建一个新的数组。

In [484]: x.view('S3').astype('U3')
Out[484]: 
array(['0', '200', '0', '200', '200', '0'], 
      dtype='<U3')
In [485]: x.view('S3').astype('U3').view(np.uint8)
Out[485]: 
array([48,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 50,  0,  0,  0, 48,
        0,  0,  0, 48,  0,  0,  0, 48,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0, 50,  0,  0,  0, 48,  0,  0,  0, 48,  0,  0,  0, 50,  0,  0,
        0, 48,  0,  0,  0, 48,  0,  0,  0, 48,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0], dtype=uint8)

unicode版本的缓冲区中有72个字节,每个字符4个字节。

np.char仍然存在,但主要是将字符串方法应用于SU类型数组。np.char.decode的功能与astype相同。

In [489]: np.char.decode(x.view('S3'))
Out[489]: 
array(['0', '200', '0', '200', '200', '0'], 
      dtype='<U3')

相关内容

最新更新