我试图从超长字符数组生成三元组数组(即连续三字母组合):
# 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
自由设置stride
和np.lib.stride_tricks.as_strided
,但是我不能强迫dtype
成为某物,这就是问题所在。
编辑
可以通过简单切片来形成非连续数组。例如:
np.empty((8, 4), 'uint32')[:, :2].view('uint64')
将在上面抛出相同的异常(从内存的角度来看,我应该可以这样做)。这种情况比上面的示例更为常见。
答案 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)