情景

我有一个4Dndarray,由多个维度(体素,dim1,dim2,dim3)的3D图像/体素组成,比如说(12个体素,96个像素,96个像素,96个像素).我的目标是从middle of the volume of m voxels个样本中抽取n slices个样本.

我已经查看了(advanced) indexing上的Numpy文档,以及解释广播的this answer文档,以及解释Numpy插入newaxisthis answer文档,但我仍然无法理解我的场景中的潜在行为.

问题

最初,我试图通过使用以下代码一次性索引数组来实现上述目的:

import numpy as np

array = np.random.rand(12, 96, 96, 96)

n = 4
m_voxels = 6
samples_range = np.arange(0, m_voxels)

middle_slices = array.shape[1] // 2
middle_slices_range = np.arange(middle_slices - n // 2, middle_slices + n // 2)

samples_from_the_middle = array[samples_range, middle_slices_range, :, :]

我没有获得形状数组(6、4、96、96),而是遇到了以下IndexError:

IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (6,) (4,)

当我try 显式或分两步为数组编制索引时,它按预期工作:

explicit_indexing = array[0:6, 46:50, :, :]
temp = array[samples_range]
samples_from_the_middle = temp[:, middle_slices_range, :, :]
explicit_indexing.shape # output: (6, 4, 96, 96)
samples_from_the_middle.shape  # output: (6, 4, 96, 96)

或者,如本answer中所述,另一种方法是:

samples_from_the_middle = array[samples_range[:, np.newaxis], middle_slices_range, :, :]  
samples_from_the_middle.shape # output: (6, 4, 96, 96)

我有以下几个问题:

  1. 为什么在显式索引(使用冒号)正常工作时,np.arange方法无法产生预期的结果,即使我们实际上是使用相同范围的整数进行索引?
  2. 为什么在第一个索引1D数组中添加newaxis似乎就解决了这个问题?

任何真知灼见都将不胜感激.

推荐答案

因此,NumPy处理索引的方式是不同的,这取决于您是使用slices(这是在执行my_array[a:b]时创建的),还是使用NumPyarray.思考它的一个有用的方法是AS cartesian products.请看此演示:

In [1]: import numpy as np

In [2]: x = np.array([[1,2,3],[4,5,6],[7,8,9]])

In [3]: x
Out[3]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

In [4]: x[0:3, 0:3]
Out[4]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

In [5]: x[np.arange(3), np.arange(3)]
Out[5]: array([1, 5, 9])

请注意,当我们使用切片时,我们会得到您想要的输出.当我们使用NumPy数组时,我们得到的是一个只有3个元素而不是9个元素的一维array.为什么?这是因为切片会自动用于创建笛卡尔积.对于来自两个切片的所有可能的值对,Python会自动生成形式为[0, 0], [0, 1], [0, 2], [1, 0], ... 的索引.

当使用NumPy数组进行索引时,情况并非如此.取而代之的是,数组被匹配elementwise.这意味着只创建了对[0, 0], [1, 1], [2, 2],并且我们只得到了3个对角元素.这与NumPy没有将1D数组视为适当的行或列向量有关,除非我们explicitly说明一个数组有多少行和列.当我们这样做时,我们使NumPy达到broadcasting,在本质上,数组沿着长度为1的轴"重复".

In [10]: x = np.array([1,2,3,4,5])

In [11]: y = np.array([6,7,8])

In [12]: from numpy import newaxis as nax

In [13]: x = x[:, nax]

In [14]: y = y[nax, :]

In [15]: x + y
Out[15]:
array([[ 7,  8,  9],
       [ 8,  9, 10],
       [ 9, 10, 11],
       [10, 11, 12],
       [11, 12, 13]])

在那里您可以看到我们获得了您在索引时所寻找的行为!来自x数组的每个元素与来自y数组的每个元素配对.

现在我们可以使用这些知识,如下所示:

In [16]: x = np.array([[1,2,3],[4,5,6],[7,8,9]])

In [17]: x
Out[17]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

In [18]: x[0:3, 0:3]
Out[18]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

In [19]: x[np.arange(3), np.arange(3)]
Out[19]: array([1, 5, 9])

In [20]: x[np.arange(3)[:, nax], np.arange(3)[nax, :]]
Out[20]:
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

我们就完了!

为了完整起见,请注意,numpy.ix_函数的存在就是为了帮助您完成这项工作.下面是一个例子:

In [21]: x = np.array([1,2,3,4,5])

In [22]: y = np.array([6,7,8])

In [23]: x, y = np.ix_(x,y)

In [24]: x
Out[24]:
array([[1],
       [2],
       [3],
       [4],
       [5]])

In [25]: y
Out[25]: array([[6, 7, 8]])

最后,所有这些都等同于使用numpy.meshgrid函数,explicitly使用xy中的每个可能的元素对创建array.但是,您不希望将其用于索引,因为同时显式创建这些配对并将它们保存在RAM中非常浪费内存.最好让麻木为你发挥它的魔力.

Python相关问答推荐

具有症状的分段函数:如何仅针对某些输入值定义函数?

GL pygame无法让缓冲区与vertextPointer和colorPointer一起可靠地工作

在函数内部使用eval(),将函数的输入作为字符串的一部分

如果条件为真,则Groupby.mean()

DataFrame groupby函数从列返回数组而不是值

如何在箱形图中添加绘制线的传奇?

numba jitClass,记录类型为字符串

从dict的列中分钟

如何将多进程池声明为变量并将其导入到另一个Python文件

Django REST Framework:无法正确地将值注释到多对多模型,不断得到错误字段名称字段对模型无效'<><>

利用Selenium和Beautiful Soup实现Web抓取JavaScript表

python中字符串的条件替换

在Python 3中,如何让客户端打开一个套接字到服务器,发送一行JSON编码的数据,读回一行JSON编码的数据,然后继续?

如何在两列上groupBy,并使用pyspark计算每个分组列的平均总价值

巨 Python :逆向猜谜游戏

如何过滤组s最大和最小行使用`transform`'

如何反转一个框架中列的值?

如何编辑此代码,使其从多个EXCEL文件的特定工作表中提取数据以显示在单独的文件中

如何为需要初始化的具体类实现依赖反转和接口分离?

时长超过24小时如何从Excel导入时长数据