numpy:如何沿多个轴拉伸基础数组?
假设我有一个这样的“种子”数组:
>>> import numpy as np
>>> seed = np.array([[2*i, 2*i + 1] for i in range(4)])
>>> seed.shape
(4, 2)
我想把这个数组“拉伸”到两个额外的维度,最终得到一个新的数组,我们称之为 extrusion
,它的形状是 (5, 4, 3, 2)。并且,对于每一对有效的索引 (i, k),在 extrusion[i, :, k, :]
这个位置的子数组(也叫“板块”)会是原始种子数组的一个副本。
那么,使用 numpy 进行这种操作的“最佳实践”是什么呢?
在下面的补充部分,我提供了几种我能想到的方法来实现这个目标,这些方法都利用了 numpy 的广播功能来获得想要的结果,但我希望能找到一种更容易理解的替代方案,特别是对于那些不熟悉 numpy 广播的人。例如,创建一个构造函数或工厂方法,接受一个“种子”和一个期望的最终形状,并在后台完成所需的拉伸操作。
谢谢!
补充:生成所需拉伸的一个简单方法是将一个形状合适的零数组和一个经过适当重塑的种子数组相加:
>>> shape = 5, 4, 3, 2
>>> zeros = np.zeros(shape, dtype=seed.dtype)
>>> extrusion = seed.reshape((1, 4, 1, 2)) + zeros
(在给 seed.reshape
的形状元组中,长度为 1 的轴就是拉伸将要发生的方向。其余轴的长度必须与期望的最终形状中的对应轴的长度匹配。)
这种方法确实能产生想要的结果;例如,[1, :, 2, :]
这个板块的内容就是种子数组的一个复制品。
>>> extrusion[1, :, 2, :]
array([[0, 1],
[2, 3],
[4, 5],
[6, 7]])
>>> seed
array([[0, 1],
[2, 3],
[4, 5],
[6, 7]])
稍微不那么复杂的方法是创建一个形状正确的接收数组,然后将种子数组(经过适当重塑后)直接赋值给它:
>>> extrusion = np.empty(shape, dtype=seed.dtype)
>>> extrusion[...] = seed.reshape((1, 4, 1, 2))
>>> extrusion[3, :, 2, :]
array([[0, 1],
[2, 3],
[4, 5],
[6, 7]])
编辑:感谢 wim 提出的对 np.zeros
和 np.empty
调用的简化建议。
1 个回答
你可以使用 np.broadcast_to
来把你的数组调整成想要的形状:
extrusion = np.broadcast_to(seed.reshape(1, 4, 1, 2), (5, 4, 3, 2))
这个方法之所以有效,是因为它和你对 extrusion[...]
的赋值原理是一样的,不过通过调整到指定的形状,你可以在一个表达式中完成这个操作。
这样做会生成原始数组的一个视图,多个结果单元格实际上是原始数组同一个单元格的视图,所以除非你完全理解这个过程,否则不要随意修改结果。如果你需要一个可以安全修改的“常规”结果,你可以复制这个广播的结果:
extrusion = np.broadcast_to(seed.reshape(1, 4, 1, 2), (5, 4, 3, 2)).copy()