假设我有一个排列数组perm
,如下所示:
perm = np.array([[0, 1, 2], [1, 2, 0], [0, 2, 1], [2, 1, 0]])
如果我想将其应用于一个轴,我可以写类似如下的内容:
v = np.arange(9).reshape(3, 3)
print(v[perm])
输出:
array([[[0, 1, 2],
[3, 4, 5],
[6, 7, 8]],
[[3, 4, 5],
[6, 7, 8],
[0, 1, 2]],
[[0, 1, 2],
[6, 7, 8],
[3, 4, 5]],
[[6, 7, 8],
[3, 4, 5],
[0, 1, 2]]])
现在我想同时将其应用于两个轴。我发现我可以通过以下方式实现:
np.array([v[tuple(np.meshgrid(p, p, indexing="ij"))] for p in perm])
但我发现它效率很低,因为它必须创建一个网格,而且还需要一个 for 循环。我在这个例子中创建了一个小数组,但实际上我有很多更大的数组和很多排列,所以我真的很想有一个像单轴版本一样快速和简单的版本。
怎么样:
p1
和的第零轴p2
只是 的“批量”维度perm
,它允许您在一次操作中执行多次排列。的另一个维度
perm
与索引相对应,沿中的第一个轴p1
和中的第二个轴对齐p2
。由于轴是正交的,因此数组被广播,基本上就像您使用的数组一样meshgrid
- 但这些仍然具有批处理维度。这是我通过手机能做到的最好的事情:)如果需要的话我可以稍后尝试澄清,但关键思想是广播。
比较:
广播索引的一个更简单(没有批量维度)的示例:
在顶部的解决方案代码中,广播是隐式的。我们不需要调用,
broadcast_arrays
因为它会在索引过程中自动发生。meshgrid
你可以摆脱这比示例数组快 5 倍:
我认为 for 循环基本上是不相关的,如果您关心进一步优化,请指定您正在使用的形状......
要同时将排列应用于两个轴而不使用循环或网格,可以使用高级索引和广播。这是一种更有效的方法:
这种方法更加高效并且避免了显式循环和meshgrid。