非连续数组的块状视图连续部分为较大大小的dtype

时间:2018-11-14 09:03:54

标签: python arrays numpy memory-layout

我试图从超长字符数组生成三元组数组(即连续三字母组合):

# data is actually load from a source file
a = np.random.randint(0, 256, 2**28, 'B').view('c')

由于复制效率不高(并且会产生诸如高速缓存未命中之类的问题),因此我使用跨步技巧直接生成了Trigram:

tri = np.lib.stride_tricks.as_strided(a, (len(a)-2,3), a.strides*2)

这将生成形状为(2**28-2, 3)的三字母组合列表,其中每一行都是一个三字母组合。现在,我想将Trigram转换为字符串列表(即S3),以便numpy更加“合理地”显示它(而不是单个字符)。

tri = tri.view('S3')

它给出了例外:

ValueError: To change to a dtype of a different size, the array must be C-contiguous

我理解通常为了创建有意义的视图,数据应该是连续的,但是此数据在“应该存在的位置”是连续的:每个三个元素都是连续的。

因此,我想知道如何将view中的连续部分np.ndarray作为较大大小的dtype ?一种更“标准”的方式会更好,同时也欢迎使用骇客的方式。看来我可以使用shape自由设置stridenp.lib.stride_tricks.as_strided,但是我不能强迫dtype成为某物,这就是问题所在。

编辑

可以通过简单切片来形成非连续数组。例如:

np.empty((8, 4), 'uint32')[:, :2].view('uint64')

将在上面抛出相同的异常(从内存的角度来看,我应该可以这样做)。这种情况比上面的示例更为常见。

1 个答案:

答案 0 :(得分:3)

如果您可以访问派生自非连续数组的连续数组,通常应该可以解决此限制。

例如,您的三字母组可以这样获得:

>>> a = np.random.randint(0, 256, 2**28, 'B').view('c')
>>> a
array([b')', b'\xf2', b'\xf7', ..., b'\xf4', b'\xf1', b'z'], dtype='|S1')
>>> np.lib.stride_tricks.as_strided(a[:0].view('S3'), ((2**28)-2,), (1,))
array([b')\xf2\xf7', b'\xf2\xf7\x14', b'\xf7\x14\x1b', ...,
       b'\xc9\x14\xf4', b'\x14\xf4\xf1', b'\xf4\xf1z'], dtype='|S3')

实际上,此示例演示了我们所需的只是在内存缓冲区底部的一个连续“存根”以进行视图转换,因为此后,由于as_strided并没有进行很多检查,因此我们基本上可以自由地进行任何操作喜欢。

似乎我们总是可以通过切片大小为0的数组来获得这样的存根。对于第二个示例:

>>> X = np.empty((8, 4), 'uint32')[:, :2]
>>> np.lib.stride_tricks.as_strided(X[:0].view(np.uint64), (8, 1), X.strides)
array([[140133325248280],
       [             32],
       [       32083728],
       [       31978800],
       [              0],
       [       29686448],
       [             32],
       [       32362720]], dtype=uint64)