Pau*_*aul 4 python numpy cython python-3.x
我有一个函数,我想使用 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
Run Code Online (Sandbox Code Playgroud)
当 dtype 是简单的东西(如 、 、 等)时,它会按预期进行编译和工作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
Run Code Online (Sandbox Code Playgroud)
该函数可以编译,但是:
in_arr = np.array(['12345', '67890', '22343'], dtype='a5')
f(in_arr)
Run Code Online (Sandbox Code Playgroud)
抛出以下错误:
---> 16 cpdef str[:] f(str[:] in_arr): 17 # arr 应该是 5 个字符字符串的 numpy 数组 18 cdef str[:] out_arr = np.zeros(in_arr.shape, dtype= 'a5')
ValueError:缓冲区数据类型不匹配,预期为“unicode 对象”,但得到了一个字符串
同样,如果我使用bytes[:],它会给出错误“缓冲区 dtype 不匹配,预期是‘字节对象’,但得到了一个字符串”——而且这甚至没有解决问题,因为我没有指定这些字符串的长度为 6。
有趣的是,我可以在结构化类型中包含固定长度的字符串,如本问题所示,但我认为这不是声明类型的正确方法。
在 Python3 会话中,您的a5数组包含字节串。
In [165]: np.array(['12345', '67890', '22343'], dtype='a5')
Out[165]:
array([b'12345', b'67890', b'22343'],
dtype='|S5')
Run Code Online (Sandbox Code Playgroud)
http://cython.readthedocs.io/en/latest/src/tutorial/strings.html
说str用Python3编译时是unicode字符串类型。
我怀疑它np.array(['12345', '67890', '22343'], dtype='U5')会被接受作为您的函数的输入数组。但复制到a5 out_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]))))
Run Code Online (Sandbox Code Playgroud)
这些函数返回一个内存视图,必须将其转换为数组才能打印。
单字节内存视图副本:
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'))
Run Code Online (Sandbox Code Playgroud)
用于view将字符串与单个字节相互转换。
我去年研究过这个问题:Cython: saving unicode in numpy array
这会像处理 2d int 数组的行一样处理 unicode 字符串;之前和之后都需要重塑。
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)
Run Code Online (Sandbox Code Playgroud)
对于字节串,类似的 2dchar版本应该可以工作。
byte5 = cython.struct(x=cython.char[5])
cpdef byte5[:] byte5copy(byte5[:] in_arr):
cdef byte5[:] out_arr = np.zeros(in_arr.shape[0], dtype='|S5')
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','four','six'], dtype='|S5')
cpy = byte5copy(narr)
print(cpy)
print(repr(np.array(cpy)))
# array([b'one', b'four', b'six'], dtype='|S5')
Run Code Online (Sandbox Code Playgroud)
C 结构体正在创建一个具有 5 个字节元素的内存视图,这些元素映射到数组S5元素。
https://github.com/cython/cython/blob/master/tests/memoryview/numpy_memoryview.pyx还有一个带有字节串的结构化数组示例。
| 归档时间: |
|
| 查看次数: |
3085 次 |
| 最近记录: |