简体   繁体   English

为什么numpy rollaxis如此令人困惑?

[英]Reason why numpy rollaxis is so confusing?

The behavior of the numpy rollaxis function confuses me. numpy rollaxis函数的行为使我感到困惑。 The documentation says: 文件说:

Roll the specified axis backwards, until it lies in a given position. 向后滚动指定的轴,直到其位于给定的位置。

And for the start parameter: 对于start参数:

The axis is rolled until it lies before this position. 轴将滚动直到其位于该位置之前。

To me, this is already somehow inconsistent. 对我来说,这已经有些矛盾了。

Ok, straight forward example (from the documentation): 好的,直接的示例(来自文档):

>>> a = np.ones((3,4,5,6))
>>> np.rollaxis(a, 1, 4).shape
(3, 5, 6, 4)

The axis at index 1 (4) is rolled backward till it lies before index 4. 向后滚动索引1(4)的轴,直到它位于索引4之前。

Now, when the start index is smaller than the axis index, we have this behavior: 现在,当start索引小于axis索引时,我们具有以下行为:

>>> np.rollaxis(a, 3, 1).shape
(3, 6, 4, 5)

Instead of shifting the axis at index 3 before index 1, it ends up at 1. 而不是将轴移到索引1之前的索引3处,而是以1结尾。

Why is that? 这是为什么? Why isn't the axis always rolled to the given start index? 为什么轴不总是滚动到给定的start索引?

NumPy v1.11 and newer includes a new function, moveaxis , that I recommend using instead of rollaxis (disclaimer: I wrote it!). NumPy v1.11和更高版本包括一个新功能moveaxis ,我建议使用它而不是rollaxis (免责声明:我写的!)。 The source axis always ends up at the destination, without any funny off-by-one issues depending on whether start is greater or less than end : 源轴始终在目标处结束,而不会出现任何有趣的“一对一”问题,具体取决于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)

Results in: 结果是:

(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)

Much of the confusion results from our human intuition - how we think about moving an axis. 大部分困惑是由人类的直觉导致的-我们如何考虑移动轴。 We could specify a number of roll steps (back or forth 2 steps), or a location in the final shape tuple, or location relative to the original shape. 我们可以指定多个滚动步骤(前后两个步骤),或者指定最终形状元组中的位置,或者相对于原始形状的位置。

I think the key to understanding rollaxis is to focus on the slots in the original shape. 我认为了解rollaxis的关键是要专注于原始形状的槽口。 The most general statement that I can come up with is: 我能想到的最一般的说法是:

Roll a.shape[axis] to the position before a.shape[start] a.shape[axis]滚动到a.shape[start]之前的位置

before in this context means the same as in list insert() . 在此上下文中, before表示与列表insert()中的含义相同。 So it is possible to insert before the end. 因此可以在结尾之前插入。

The basic action of rollaxis is: rollaxis的基本动作是:

axes = list(range(0, n))
axes.remove(axis)
axes.insert(start, axis)
return a.transpose(axes)

If axis<start , then start-=1 to account for the remove action. 如果axis<start ,则start-=1表示remove操作。

Negative values get +=n , so rollaxis(a,-2,-3) is the same as np.rollaxis(a,2,1) . 负值+=n ,因此rollaxis(a,-2,-3)np.rollaxis(a,2,1) eg a.shape[-3]==a.shape[1] . 例如a.shape[-3]==a.shape[1] List insert also allows a negative insert position, but rollaxis doesn't make use of that feature. 列表insert还允许插入位置为负数,但是rollaxis不使用该功能。

So the keys are understanding that remove/insert pair of actions, and understanding transpose(x) . 因此,关键在于理解remove/insert动作对,以及理解transpose(x)

I suspect rollaxis is intended to be a more intuitive version of transpose . 我怀疑rollaxis旨在成为transpose的更直观版本。 Whether it achieves that or not is another question. 是否达到目标是另一个问题。


You suggest either omitting the start-=1 or applying across the board 您建议省略start-=1或全面申请

Omitting it doesn't change your 2 examples. 省略它不会更改您的2个示例。 It only affects the rollaxis(a,1,4) case, and axes.insert(4,1) is the same as axes.insert(3,1) when axes is [0,2,3] . 它仅影响rollaxis(a,1,4)的情况下,和axes.insert(4,1)是相同的axes.insert(3,1)axes[0,2,3] The 1 is still placed at the end. 1仍放置在末尾。 Changing that test a bit: 稍微更改一下测试:

np.rollaxis(a,1,3).shape
# (3, 5, 4, 6)   # a.shape[1](4) placed before a.shape[3](6)

without the -=1 没有-=1

# transpose axes == [0, 2, 3, 1]
# (3, 5, 6, 4)  # the 4 is placed at the end, after 6

If instead -=1 applies always 如果相反,则-=1始终适用

np.rollaxis(a,3,1).shape
#  (3, 6, 4, 5)

becomes 变成

(6, 3, 4, 5)

now the 6 is before the 3 , which was the original a.shape[0] . 现在63之前,这是原始的a.shape[0] After the roll 3 is the the a.shape[1] . 3a.shape[1] But that's a different roll specification. 但这是不同的roll规格。

It comes down to how start is defined. 取决于如何定义start Is a postion in the original order, or a position in the returned order? 是原始顺序中的位置,还是返回顺序中的位置?


If you prefer to think of start as an index position in the final shape, wouldn't it be simpler to drop the before part and just say 'move axis to dest slot'? 如果您更喜欢将start视为最终形状中的索引位置,那么放下before一部分并说“将axis移动到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])

Simply dropping the -=1 test might do the trick (omiting the handling of negative numbers and boundaries) 只需删除-=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' is the index of the axis to be moved starting from 0. In my example the axis at position 0 is 1. 'axis'是要从0开始移动的轴的索引。在我的示例中,位置0的轴为1。

'start' is the index (again starting at 0) of the axis that we would like to move our selected axis before. “开始”是我们要在其之前移动选定轴的轴的索引(再次从0开始)。

So, if start=2, the axis at position 2 is 3, therefor the selected axis will be before the 3. 因此,如果start = 2,则位置2处的轴为3,因此所选轴将位于3之前。

Examples: 例子:

>>> 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)

So, after the roll the number at axis before the roll will be placed just before the number at start before the roll. 因此,在滚动之后,在滚动之前的轴上的数字将被放置在滚动开始之前的数字之前。

If you think of rollaxis like this it is very simple and makes perfect sense, though it's strange that they chose to design it this way. 如果您这样考虑侧倾轴,那么它很简单并且很有意义,尽管他们选择以这种方式设计很奇怪。

So, what happens when axis and start are the same? 那么,当轴和起点相同时会发生什么? Well, you obviously can't put a number before itself, so the number doesn't move and the instruction becomes a no-op. 好吧,您显然不能在其前面加上数字,因此该数字不会移动并且该指令将变为无操作。

Examples: 例子:

>>> 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)

How about moving the axis to the end? 如何将轴移动到末端? Well, there's no number after the end, but you can specify start as after the end. 好吧,结束号后面没有数字,但是您可以指定开始号为结束号。

Example: 例:

>>> 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM