numpy rollaxis 如此混乱的原因是什么?
Reason why numpy rollaxis is so confusing?
numpy rollaxis 函数的行为让我感到困惑。
documentation 表示:
Roll the specified axis backwards, until it lies in a given position.
对于 start
参数:
The axis is rolled until it lies before this position.
对我来说,这已经有点不一致了。
好的,直接示例(来自文档):
>>> a = np.ones((3,4,5,6))
>>> np.rollaxis(a, 1, 4).shape
(3, 5, 6, 4)
索引 1 (4) 处的轴向后滚动,直到位于索引 4 之前。
现在,当 start
索引小于 axis
索引时,我们有这样的行为:
>>> np.rollaxis(a, 3, 1).shape
(3, 6, 4, 5)
不是在索引 1 之前在索引 3 处移动轴,而是在 1 处结束。
这是为什么?为什么轴不总是滚动到给定的 start
索引?
很多困惑源于我们人类的直觉——我们如何看待移动轴。我们可以指定滚动步数(前后 2 步),或最终形状元组中的位置,或相对于原始形状的位置。
我认为理解rollaxis
的关键是关注原始形状中的槽。我能想到的最一般的说法是:
将a.shape[axis]
滚动到a.shape[start]
之前的位置
before
在此上下文中的含义与列表 insert()
中的相同。所以在结尾之前插入是可以的。
rollaxis
的基本动作是:
axes = list(range(0, n))
axes.remove(axis)
axes.insert(start, axis)
return a.transpose(axes)
如果 axis<start
,则 start-=1
占 remove
操作。
负值得到 +=n
,因此 rollaxis(a,-2,-3)
与 np.rollaxis(a,2,1)
相同。例如a.shape[-3]==a.shape[1]
。列表 insert
也允许负插入位置,但 rollaxis
没有使用该功能。
所以关键是理解 remove/insert
对动作,并理解 transpose(x)
.
我怀疑 rollaxis
是 transpose
的更直观版本。它是否实现了那是另一个问题。
您建议省略 start-=1
或全面应用
省略它不会改变您的 2 个示例。它只影响 rollaxis(a,1,4)
的情况,当 axes
为 [0,2,3]
时,axes.insert(4,1)
与 axes.insert(3,1)
相同。 1
仍然放在最后。稍微改变一下测试:
np.rollaxis(a,1,3).shape
# (3, 5, 4, 6) # a.shape[1](4) placed before a.shape[3](6)
没有 -=1
# transpose axes == [0, 2, 3, 1]
# (3, 5, 6, 4) # the 4 is placed at the end, after 6
如果相反 -=1
始终适用
np.rollaxis(a,3,1).shape
# (3, 6, 4, 5)
变成
(6, 3, 4, 5)
现在 6
在 3
之前,这是原来的 a.shape[0]
。 roll 3
之后是 a.shape[1]
。但这是一个不同的 roll
规范。
归结为 start
是如何定义的。是原订单中的位置,还是退货订单中的位置?
如果你更愿意将start
视为最终形状中的索引位置,那么删除before
部分并直接说'move axis
to dest
slot'不是更简单吗?
myroll(a, axis=3, dest=0) => (np.transpose(a,[3,0,1,2])
myroll(a, axis=1, dest=3) => (np.transpose(a,[0,2,3,1])
简单地删除 -=1
测试可能会成功(忽略负数和边界的处理)
def myroll(a,axis,dest):
x=list(range(a.ndim))
x.remove(axis)
x.insert(dest,axis)
return a.transpose(x)
a = np.arange(1*2*3*4*5).reshape(1,2,3,4,5)
np.rollaxis(a,axis,start)
'axis' 是要从 0 开始移动的轴的索引。在我的示例中,位置 0 处的轴是 1。
'start' 是我们希望在之前移动所选轴的轴的索引(再次从 0 开始)。
因此,如果start=2,则位置2的轴为3,因此选择的轴将在3之前。
示例:
>>> np.rollaxis(a,0,2).shape # the 1 will be before the 3.
(2, 1, 3, 4, 5)
>>> np.rollaxis(a,0,3).shape # the 1 will be before the 4.
(2, 3, 1, 4, 5)
>>> np.rollaxis(a,1,2).shape # the 2 will be before the 3.
(1, 2, 3, 4, 5)
>>> np.rollaxis(a,1,3).shape # the 2 will be before the 4.
(1, 3, 2, 4, 5)
因此,在滚动之后,滚动之前轴上的数字将被放置在滚动之前开始处的数字之前。
如果你这样想 rollaxis,它非常简单而且非常有意义,尽管他们选择这样设计它很奇怪。
那么,当 axis 和 start 相同时会发生什么?好吧,你显然不能把数字放在它自己之前,所以数字不会移动,指令变成空操作。
示例:
>>> np.rollaxis(a,1,1).shape # the 2 can't be moved to before the 2.
(1, 2, 3, 4, 5)
>>> np.rollaxis(a,2, 2).shape # the 3 can't be moved to before the 3.
(1, 2, 3, 4, 5)
把坐标轴移到最后怎么样?好吧,结束后没有数字,但你可以指定结束后开始。
示例:
>>> np.rollaxis(a,1,5).shape # the 2 will be moved to the end.
(1, 3, 4, 5, 2)
>>> np.rollaxis(a,2,5).shape # the 3 will be moved to the end.
(1, 2, 4, 5, 3)
>>> np.rollaxis(a,4,5).shape # the 5 is already at the end.
(1, 2, 3, 4, 5)
NumPy v1.11 和更新版本包含一个新函数 moveaxis
,我建议使用它来代替 rollaxis
(免责声明:我写的!)。源轴总是在目的地结束,没有任何有趣的差一问题取决于 start
是大于还是小于 end
:
import numpy as np
x = np.zeros((1, 2, 3, 4, 5))
for i in range(5):
print(np.moveaxis(x, 3, i).shape)
结果:
(4, 1, 2, 3, 5)
(1, 4, 2, 3, 5)
(1, 2, 4, 3, 5)
(1, 2, 3, 4, 5)
(1, 2, 3, 5, 4)
numpy rollaxis 函数的行为让我感到困惑。 documentation 表示:
Roll the specified axis backwards, until it lies in a given position.
对于 start
参数:
The axis is rolled until it lies before this position.
对我来说,这已经有点不一致了。
好的,直接示例(来自文档):
>>> a = np.ones((3,4,5,6))
>>> np.rollaxis(a, 1, 4).shape
(3, 5, 6, 4)
索引 1 (4) 处的轴向后滚动,直到位于索引 4 之前。
现在,当 start
索引小于 axis
索引时,我们有这样的行为:
>>> np.rollaxis(a, 3, 1).shape
(3, 6, 4, 5)
不是在索引 1 之前在索引 3 处移动轴,而是在 1 处结束。
这是为什么?为什么轴不总是滚动到给定的 start
索引?
很多困惑源于我们人类的直觉——我们如何看待移动轴。我们可以指定滚动步数(前后 2 步),或最终形状元组中的位置,或相对于原始形状的位置。
我认为理解rollaxis
的关键是关注原始形状中的槽。我能想到的最一般的说法是:
将a.shape[axis]
滚动到a.shape[start]
before
在此上下文中的含义与列表 insert()
中的相同。所以在结尾之前插入是可以的。
rollaxis
的基本动作是:
axes = list(range(0, n))
axes.remove(axis)
axes.insert(start, axis)
return a.transpose(axes)
如果 axis<start
,则 start-=1
占 remove
操作。
负值得到 +=n
,因此 rollaxis(a,-2,-3)
与 np.rollaxis(a,2,1)
相同。例如a.shape[-3]==a.shape[1]
。列表 insert
也允许负插入位置,但 rollaxis
没有使用该功能。
所以关键是理解 remove/insert
对动作,并理解 transpose(x)
.
我怀疑 rollaxis
是 transpose
的更直观版本。它是否实现了那是另一个问题。
您建议省略 start-=1
或全面应用
省略它不会改变您的 2 个示例。它只影响 rollaxis(a,1,4)
的情况,当 axes
为 [0,2,3]
时,axes.insert(4,1)
与 axes.insert(3,1)
相同。 1
仍然放在最后。稍微改变一下测试:
np.rollaxis(a,1,3).shape
# (3, 5, 4, 6) # a.shape[1](4) placed before a.shape[3](6)
没有 -=1
# transpose axes == [0, 2, 3, 1]
# (3, 5, 6, 4) # the 4 is placed at the end, after 6
如果相反 -=1
始终适用
np.rollaxis(a,3,1).shape
# (3, 6, 4, 5)
变成
(6, 3, 4, 5)
现在 6
在 3
之前,这是原来的 a.shape[0]
。 roll 3
之后是 a.shape[1]
。但这是一个不同的 roll
规范。
归结为 start
是如何定义的。是原订单中的位置,还是退货订单中的位置?
如果你更愿意将start
视为最终形状中的索引位置,那么删除before
部分并直接说'move axis
to dest
slot'不是更简单吗?
myroll(a, axis=3, dest=0) => (np.transpose(a,[3,0,1,2])
myroll(a, axis=1, dest=3) => (np.transpose(a,[0,2,3,1])
简单地删除 -=1
测试可能会成功(忽略负数和边界的处理)
def myroll(a,axis,dest):
x=list(range(a.ndim))
x.remove(axis)
x.insert(dest,axis)
return a.transpose(x)
a = np.arange(1*2*3*4*5).reshape(1,2,3,4,5)
np.rollaxis(a,axis,start)
'axis' 是要从 0 开始移动的轴的索引。在我的示例中,位置 0 处的轴是 1。
'start' 是我们希望在之前移动所选轴的轴的索引(再次从 0 开始)。
因此,如果start=2,则位置2的轴为3,因此选择的轴将在3之前。
示例:
>>> np.rollaxis(a,0,2).shape # the 1 will be before the 3.
(2, 1, 3, 4, 5)
>>> np.rollaxis(a,0,3).shape # the 1 will be before the 4.
(2, 3, 1, 4, 5)
>>> np.rollaxis(a,1,2).shape # the 2 will be before the 3.
(1, 2, 3, 4, 5)
>>> np.rollaxis(a,1,3).shape # the 2 will be before the 4.
(1, 3, 2, 4, 5)
因此,在滚动之后,滚动之前轴上的数字将被放置在滚动之前开始处的数字之前。
如果你这样想 rollaxis,它非常简单而且非常有意义,尽管他们选择这样设计它很奇怪。
那么,当 axis 和 start 相同时会发生什么?好吧,你显然不能把数字放在它自己之前,所以数字不会移动,指令变成空操作。
示例:
>>> np.rollaxis(a,1,1).shape # the 2 can't be moved to before the 2.
(1, 2, 3, 4, 5)
>>> np.rollaxis(a,2, 2).shape # the 3 can't be moved to before the 3.
(1, 2, 3, 4, 5)
把坐标轴移到最后怎么样?好吧,结束后没有数字,但你可以指定结束后开始。
示例:
>>> np.rollaxis(a,1,5).shape # the 2 will be moved to the end.
(1, 3, 4, 5, 2)
>>> np.rollaxis(a,2,5).shape # the 3 will be moved to the end.
(1, 2, 4, 5, 3)
>>> np.rollaxis(a,4,5).shape # the 5 is already at the end.
(1, 2, 3, 4, 5)
NumPy v1.11 和更新版本包含一个新函数 moveaxis
,我建议使用它来代替 rollaxis
(免责声明:我写的!)。源轴总是在目的地结束,没有任何有趣的差一问题取决于 start
是大于还是小于 end
:
import numpy as np
x = np.zeros((1, 2, 3, 4, 5))
for i in range(5):
print(np.moveaxis(x, 3, i).shape)
结果:
(4, 1, 2, 3, 5)
(1, 4, 2, 3, 5)
(1, 2, 4, 3, 5)
(1, 2, 3, 4, 5)
(1, 2, 3, 5, 4)