使用numpy数组时出现奇怪的行为

3
我希望有人能够解释一下我在numpy数组中观察到的以下行为:
>>> import numpy as np
>>> data_block=np.zeros((26,480,1000))
>>> indices=np.arange(1000)
>>> indices.shape
(1000,)
>>> data_block[0,:,:].shape
(480, 1000)            #fine and dandy
>>> data_block[0,:,indices].shape
(1000, 480)            #what happened????  why the transpose????
>>> ind_slice=np.arange(300)    # this is more what I really want.
>>> data_block[0,:,ind_slice].shape
(300, 480)     # transpose again!   arghhh!

我不理解这个转置行为,它让我想做的事情非常不方便。有人能给我解释一下吗?如果有方法可以获取data_block的子集,那就太好了。


实际规则非常简单。如果花式索引(标量在这方面也是花式的,这可能很奇怪,但...)都是连续的,numpy可以猜测您想要放置来自花式索引的维度。如果它们不是连续的,则将它们放在第一位。如果您记得所有花式索引都“作为一个”工作,那么这是有意义的。 - seberg
2个回答

3
您可以通过以下方式实现所需的结果:
>>> data_block[0,:,:][:,ind_slice].shape
(480L, 300L)

我承认我并不完全理解numpy索引的复杂性,但文档似乎暗示了你所遇到的问题:
基本切片中,如果在切片元组中有多个非“:”条目,则会像使用单个非“:”条目重复应用切片一样,其中非“:”条目被连续取出(所有其他非“:”条目替换为“:”)。因此,x[ind1,...,ind2,:] 在基本切片下的行为类似于 x[ind1][...,ind2,:]
警告:上述内容对于高级切片不成立。
当选择对象obj是非元组序列对象、ndarray(数据类型为整数或布尔值)或至少具有一个序列对象或ndarray(数据类型为整数或布尔值)的元组时,会触发高级索引。
因此,通过使用您的ind_slice数组进行索引,而不是常规切片,您正在触发该行为。
文档本身表示这种索引“可能有些令人难以理解”,因此我们都遇到了困难 :-).

1
一旦您了解了花式索引的工作原理,就不会感到太惊讶。如果您使用列表或数组作为索引,则它们必须具有相同的形状,或者可以广播到一个公共形状。该形状将是返回数组的基本形状。如果有切片索引,则基本形状数组中的每个条目都将是多维的,因此基本形状会扩展额外的条目。虽然这可能看起来是一个奇怪的选择,但它确实是与多维花式索引一致的唯一选择。例如,尝试想象一下,如果您执行以下操作,您期望的返回形状将是什么:
>>> ind_slice=np.arange(16).reshape(4, 4)
>>> data_block[ind_slice, :, ind_slice].shape
(4, 4, 480) # No, (4, 4, 480, 4, 4) is not a better option

有几种方法可以得到你想要的结果。对于你提出的特定情况,最明显的方法是不使用高级索引,因为你可以通过切片获得你需要的结果:

>>> data_block[0, :, :300].shape
(480, 300)

如果您确实需要高级索引,可以使用可广播数组替换切片:
>>> data_block[0, np.arange(480)[:, None], ind_slice].shape
(480, 300)

你可能需要查看np.ogridnp.mgrid,如果你需要用数组替换更复杂的切片。

感谢你的勇敢尝试来解释它,Jaime。但我仍然觉得非常困惑。谢谢。 - bob.sacamento

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接