Python Cython指定固定长度字符串的numpy数组

Python Cython指定固定长度字符串的numpy数组,python,python-3.x,numpy,cython,Python,Python 3.x,Numpy,Cython,我有一个我想使用Cython的函数,它涉及处理大量固定长度的字符串。对于标准cython函数,我可以声明如下数组类型: cpdef double[:] g(double[:] in_arr): cdef double[:] out_arr = np.zeros(in_arr.shape, dtype='float64') cdef i for i in range(len(in_arr)): out_arr[i] = in_arr[i] ret

我有一个我想使用Cython的函数,它涉及处理大量固定长度的字符串。对于标准cython函数,我可以声明如下数组类型:

cpdef double[:] g(double[:] in_arr):
    cdef double[:] out_arr = np.zeros(in_arr.shape, dtype='float64')

    cdef i
    for i in range(len(in_arr)):
        out_arr[i] = in_arr[i]

    return out_arr
当数据类型很简单时,如
int32
float
double
等,这会按照预期进行编译和工作。但是,我不知道如何创建固定长度字符串的类型化内存视图,例如,与
np.dtype('a5')
等效

如果我使用这个:

cpdef str[:] f(str[:] in_arr):
    # arr should be a numpy array of 5-character strings
    cdef str[:] out_arr = np.zeros(in_arr.shape, dtype='a5')

    cdef i
    for i in range(len(in_arr)):
        out_arr[i] = in_arr[i]

    return out_arr
该函数可编译,但这是:

in_arr = np.array(['12345', '67890', '22343'], dtype='a5')
f(in_arr)
引发以下错误:

--->16 cpdef str[:]f(str[:]in_arr): 17#arr应该是5个字符字符串的numpy数组 18 cdef str[:]out_arr=np.zero(in_arr.shape,dtype='a5')

ValueError:缓冲区数据类型不匹配,应为“unicode对象”,但得到一个 串

类似地,如果我使用
bytes[:]
,它会给出错误“缓冲区数据类型不匹配,预期为'bytes object',但得到了一个字符串”-这甚至没有解决问题,因为我没有指定这些字符串的长度为6


有趣的是,我可以像中一样在结构化类型中包含固定长度的字符串,但我认为这不是声明类型的正确方法。

在Python3会话中,您的
a5
数组包含ByTestring

In [165]: np.array(['12345', '67890', '22343'], dtype='a5')
Out[165]: 
array([b'12345', b'67890', b'22343'], 
      dtype='|S5')
表示当使用Python3编译时,
str
是unicode字符串类型

我怀疑
np.array(['12345','67890','22343',dtype='U5')
会被接受为函数的输入数组。但是,复制到
a5
out\u arr
会有问题

对象版本 此循环的对象版本可以工作:

cpdef str[:] objcopy(str[:] in_arr):
    cdef str[:] out_arr = np.zeros(in_arr.shape[0], dtype=object)
    cdef int N
    N = in_arr.shape[0]
    for i in range(N):
        out_arr[i] = in_arr[i]
    return out_arr

narr = np.array(['one','two','three'], dtype=object)
cpy = objcopy(narr)
print(cpy)
print(np.array(cpy))
print(np.array(objcopy(np.array([None,'one', 23.4]))))
这些函数返回一个memoryview,它必须转换为数组才能打印

单字符版本 单字节存储器视图副本:

cpdef char[:] chrcopy(char[:] in_arr):
    cdef char[:] out_arr = np.zeros(in_arr.shape[0], dtype='uint8')
    cdef int N
    N = in_arr.shape[0]
    for i in range(N):
        out_arr[i] = in_arr[i]
    return out_arr
print(np.array(chrcopy(np.array([b'one',b'two',b'three']).view('S1'))).view('S5'))
使用
视图
将字符串转换为单个字节并返回

二维unicode版本 我去年研究过这个问题:

这将处理unicode字符串,就像它们是2d int数组的行一样;前后都需要整形

cpdef int[:,:] int2dcopy(int[:,:] in_arr):
    cdef int[:,:] out_arr = np.zeros((in_arr.shape[0], in_arr.shape[1]), dtype=int)
    cdef int N
    N = in_arr.shape[0]
    for i in range(N):
        out_arr[i,:] = in_arr[i,:]
    return out_arr

narr = np.array(['one','two','three', 'four', 'five'], dtype='U5')
cpy = int2dcopy(narr.view('int').reshape(-1,5))
print(cpy)
print(np.array(cpy))
print(np.array(cpy).view(narr.dtype)) # .reshape(-1)
对于bytestring,类似的2d
char
版本应该可以工作

c结构版本 C结构正在创建一个带有5字节元素的memoryview,它映射到数组
S5
元素上


还有一个带有bytestrings的结构化数组示例。

这并不能解释
字节[:]
不起作用的事实。去年我考虑将unicode字符串作为2d数组的行处理,
U5
是一个5列
int
行。还没有时间查看您的编辑,但如果您仍在处理这个问题,无需关注unicode部分。如果有必要,我可以使用bytestring,它们是固定长度的ASCII标识符。到目前为止,我的最佳尝试对unicode和字节也适用,只是使用
int
v
uint8
(4字节v1/elment)。是的,看看这个,似乎
对象版本是最好的,但是即使放弃了使用
memoryview
对象的想法,为什么没有一个版本可以做类似于
cdef np.ndarray[np.dtype('a6')]arr=…
?将其视为一个对象数组而不是一个固定长度的字符串数组似乎是在丢弃非常有价值的类型和内存布局信息。
In [165]: np.array(['12345', '67890', '22343'], dtype='a5')
Out[165]: 
array([b'12345', b'67890', b'22343'], 
      dtype='|S5')