Cython: ndarray字符串的内存视图(或直接使用ndarray索引)

6

如何指定包含字符串的ndarray的内存视图?

char [:], char* [:]等方法均不可用。

为了说明我的问题,我的函数abc(...)的定义如下:

cdef void abc(char[:] in_buffer):
    cdef char * element
    element = address(in_buffer[1])
    ...

def main():
    cdef Py_ssize_t i, n = 100

    a = np.array(['ABC', 'D', 'EFGHI'])
    for i in range(n):
        abc(a)

如果无法使用memoryview,我是否可以自己实现直接数组访问?我需要在函数abc(...)中避免GIL。

编辑1:回复Bi Rico的答案。

我的目标是为了函数abc(...)释放GIL,并在其中使用c字符串函数处理ndarray in_buffer的字符串元素。也就是像下面这样做:

cdef void abc(char[:, ::1] in_buffer) nogil:
    cdef int max_elt_length = in_buffer.shape[1]+1
    cdef char element[max_elt_length+1]
    cdef int length

    for i in range(in_buffer.shape[0]+1):  # is this equivalent to in_buffer.dtype.itemsize + 1 ?
       element[max_elt_length] = 0   # add null-terminator for full-size elements
       memcpy(element, address(buffer[i, 0]), max_length)
       length = strlen(element)
       ...
1个回答

8
问题在于numpy数组的数据类型必须具有固定的大小。当您创建一个“字符串”数组时,实际上是创建了一个固定长度的字符数组的数组。请尝试以下方法:
import numpy as np

array = np.array(["cat", "in", "a", "hat"])
array[2] = "Seuss"
print(array)
# ['cat' 'in' 'Seu' 'hat']
print(array.dtype)
# dtype('|S3')
print(array.dtype.itemsize)
# 3

考虑到这一点,您可以尝试像这样的操作:
cdef void abc(char[:, ::1] in_buffer):
    cdef char * element
    element = address(in_buffer[1, 0])

当您将数组传递给 abc 时,您需要执行以下操作:
a = np.array(['ABC', 'D', 'EFGHI'])
array_view = a.view('uint8').reshape(a.size, a.dtype.itemsize)
abc(array_view)

这只是一种方法,但在不了解你要做什么的情况下,我建议使用这种方法。


谢谢你的回答!我试图让我的问题保持通用,以避免分散注意力。回答你的问题:我正在尝试使用C字符串函数在for循环中处理ndarray的字符串元素。我已经编辑了我的问题并添加了额外的解释。你能否检查一下我是否正确地应用了你建议的技巧?你能否指出char[:, ::1]内存视图定义中的::1部分的文档说明? - ARF
::1 表示输入缓冲区应该是 C 连续的。你的更新代码原则上看起来没问题,但是有一些差一的错误。我认为应该是 range(in_buffer.shape[0])max_elt_length = in_buffer.shape[1]。最后,in_buffer 没有 dtype 属性。in_buffer.shape[0] 是原始数组中字符串的数量。 - Bi Rico
感谢您的帮助,我现在成功让我的函数运行起来了。 - ARF

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接