将带有字符串的结构化numpy数组传递给cython函数

29

我正在尝试使用Cython创建一个函数,该函数通过定义Cython结构类型来接受NumPy结构化数组或记录数组。假设我有以下数据:

a = np.recarray(3, dtype=[('a', np.float32),  ('b', np.int32), ('c', '|S5'), ('d', '|S3')])
a[0] = (1.1, 1, 'this\0', 'to\0')
a[1] = (2.1, 2, 'that\0', 'ta\0')
a[2] = (3.1, 3, 'dogs\0', 'ot\0')

(注:下面描述的问题在有或没有空终止符的情况下都会出现)
然后我有了Cython代码:
import numpy as np
cimport numpy as np

cdef packed struct tstruct:
    np.float32_t a
    np.int32_t b
    char[5] c
    char[3] d

def test_struct(tstruct[:] x):
    cdef:
        int k
        tstruct y

    for k in xrange(3):
        y = x[k]
        print y.a, y.b, y.c, y.d

当我尝试运行test_struct(a)时,出现错误:

ValueError: Expected a dimension of size 5, got 8

如果数组和对应的结构体被重新排序,使得包含字符串的字段不相邻,那么函数就会按预期工作。看起来Cython函数没有正确检测到 c 和d字段之间的边界,并认为您传递了长度总和的字符数组。
除了重新排列数据(这是可能但不理想的),还有其他方法将具有固定长度字符串数据的记录数组传递给Cython吗?
更新:这似乎是一个潜在的Cython错误。请参见Cython谷歌小组上的以下讨论,其中暗示问题出现的位置:

https://groups.google.com/forum/#!topic/cython-users/TbLbXdi0_h4

更新2:该错误已于2014年2月23日在Github的主Cython分支中得到修复,并计划将补丁包含在v0.20.2中:https://github.com/cython/cython/commit/58d9361e0a6d4cb3d4e87775f78e0550c2fea836

2
我没有解决方案,只有同情。我使用Cython 0.20时也遇到了相同的错误。使用使用align=True创建的dtype结构化数组也无济于事(请参见http://docs.scipy.org/doc/numpy/reference/generated/numpy.dtype.html)。 - Warren Weckesser
@WarrenWeckesser 我在cython列表中发布了类似的内容,希望能在那里得到一些进展。 - JoshAdel
嗯,也许有一些魔法可以将这两个字符串相加吗?(这将使它变成8而不是5)。如果在这两个字符串之间插入一个整数数据类型会发生什么?或者删掉最后一个字符串看看会发生什么。 - Magellan88
@Magellan88 正如我在原始问题中提到的,如果这两个字符串不相邻(例如,在 cd 之间放置 b),那么一切都按预期工作。问题在于相邻字符串之间的边界似乎无法正确检测。 - JoshAdel
@Magellan88 没有什么魔法。Cython为类型检查生成代码。我跟着它走,找到了循环遍历结构元素以确定长度等的代码片段。由于某种原因,当两个字符串一个接一个时,它只是将两个字段的长度相加。对我来说不是完全清楚为什么,以及哪里出了问题,因为我不熟悉Cython的代码。 - Ricardo Cárdenes
1个回答

1

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