我的ndarray
尺寸为n>1
。我有一个布尔数组ok0
对应于我想要选择的行,另一个布尔数组ok1
对应于我想要选择的列。我想要包括所有“页面”。所以我尝试Z[ok0, ok1, :]
,其中ok0
是带有ok0.size == Z.shape[0]
的1-D布尔数组,ok1
是带ok1.size == Z.shape[1]
的布尔数组。有没有办法直接使用这些布尔数组索引我的nd-array?
代码片段描绘了千言万语。
In [50]: Z = arange(7*8*9).reshape(7, 8, 9)
In [51]: ok0 = Z.sum(1).sum(1)%10<3
In [52]: ok1 = Z.sum(0).sum(1)%10<5
In [53]: ok0.shape
Out[53]: (7,)
In [54]: ok1.shape
Out[54]: (8,)
In [55]: Z[ok0, :, :].shape
Out[55]: (3, 8, 9)
In [56]: Z[:, ok1, :].shape
Out[56]: (7, 4, 9)
In [57]: Z[ok0, ok1, :].shape
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-57-ebba5b9a19dd> in <module>()
----> 1 Z[ok0, ok1, :].shape
ValueError: shape mismatch: objects cannot be broadcast to a single shape
可以间接实现所需的效果,如下所示:
In [58]: Z[ok0, :, :][:, ok1, :].shape
Out[58]: (3, 4, 9)
如果我将ok0
和ok1
从布尔数组转换为整数数组,我可以使用this answer to Selecting specific rows and columns from NumPy array中提供的解决方案:
In [88]: ok0i = ok0.nonzero()[0]
In [89]: ok1i = ok1.nonzero()[0]
In [90]: Z[ok0i[:, newaxis], ok1i, :].shape
Out[90]: (3, 4, 9)
但是,这不适用于原始布尔数组:
In [87]: Z[ok0[:, newaxis], ok1, :].shape
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-87-7e9fa28c47fa> in <module>()
----> 1 Z[ok0[:, newaxis], ok1, :].shape
ValueError: shape mismatch: objects cannot be broadcast to a single shape
为什么这不起作用 - 这里出了什么问题?并且(如何)我可以一次性实现所需的效果,而不像我在命令58中那样重复我的完整索引(可能很长)?
答案 0 :(得分:0)
由于您希望根据某些条件选择整行和列,我认为np.take
可能是解决此问题的合适解决方案,而无需将现有方法更改为确定所需的行和列,{ {1}}和ok0
。
ok1
这将首先选择result = np.take(np.take(Z, np.where(ok0)[0], axis=0), np.where(ok1)[0], axis=1)
所在的所有行(axis=0
),并从该子集中选择ok0==True
所有列(axis=1
)。在ok1==True
np.where
之后需要[0]输出包含索引的数组元组(数组([]),但是你只需要{{1的索引数组}}
此方法的另一个优点是np.where
也比使用ndarrays的“花式”索引更有效。
答案 1 :(得分:0)
Re:在一个阶段做掩码选择:
In [152]: result = Z[ok0[:, np.newaxis] & ok1].reshape(ok0.sum(), ok1.sum(),
*Z.shape[2:])
In [153]: result.shape
Out[153]: (3, 4, 9)
In [154]: (result == Z[ok0][:, ok1]).all()
Out[154]: True
Re:长索引:您可以省略任意数量的尾随维度
用省略号(...
)替换任意数量的前导维度
完整地指定所有最后的尺寸。
In [155]: Z[0]
Out[155]:
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8],
[ 9, 10, 11, 12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23, 24, 25, 26],
[27, 28, 29, 30, 31, 32, 33, 34, 35],
[36, 37, 38, 39, 40, 41, 42, 43, 44],
[45, 46, 47, 48, 49, 50, 51, 52, 53],
[54, 55, 56, 57, 58, 59, 60, 61, 62],
[63, 64, 65, 66, 67, 68, 69, 70, 71]])
In [156]: Z[...,0]
Out[156]:
array([[ 0, 9, 18, 27, 36, 45, 54, 63],
[ 72, 81, 90, 99, 108, 117, 126, 135],
[144, 153, 162, 171, 180, 189, 198, 207],
[216, 225, 234, 243, 252, 261, 270, 279],
[288, 297, 306, 315, 324, 333, 342, 351],
[360, 369, 378, 387, 396, 405, 414, 423],
[432, 441, 450, 459, 468, 477, 486, 495]])
掩码选择有效,因为我们可以使用高深度布尔掩码来获取元素 符合条件:
In [157]: arr
Out[157]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [158]: (arr % 2 == 0).astype(int)
Out[158]:
array([[1, 0, 1],
[0, 1, 0],
[1, 0, 1]])
In [159]: arr[arr % 2 == 0]
Out[159]: array([0, 2, 4, 6, 8])
可以使用您已使用的广播技巧生成掩码:
In [160]: ok0 = arr.sum(1)%10<3
In [161]: ok1 = arr.sum(0)%10<5
In [162]: (ok0[:, np.newaxis] & ok1).astype(int)
Out[162]:
array([[0, 0, 0],
[0, 1, 0],
[0, 1, 0]])
In [163]: arr[ok0[:, np.newaxis] & ok1]
Out[163]: array([4, 7])
但是你可以注意到这些元素是狂暴的,每个面具都要计算 恢复形状:
In [164]: arr[ok0[:, np.newaxis] & ok1].reshape(ok0.sum(), ok1.sum())
Out[164]:
array([[4],
[7]])