jpp*_*jpp 4 python arrays indexing numpy array-broadcasting
与此问题相关,我通过布尔数组和广播遇到了索引行为,我不明白。我们知道可以使用整数索引和广播在 2 维中索引 NumPy 数组。这是在文档中指定的:
a = np.array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
b1 = np.array([False, True, True])
b2 = np.array([True, False, True, False])
c1 = np.where(b1)[0] # i.e. [1, 2]
c2 = np.where(b2)[0] # i.e. [0, 2]
a[c1[:, np.newaxis], c2] # or a[c1[:, None], c2]
array([[ 4, 6],
[ 8, 10]])
Run Code Online (Sandbox Code Playgroud)
但是,这同样不适用于布尔数组。
a[b1[:, None], b2]
IndexError: too many indices for array
Run Code Online (Sandbox Code Playgroud)
替代方案numpy.ix_适用于整数和布尔数组。这似乎是因为ix_对布尔数组执行特定操作以确保一致处理。
assert np.array_equal(a[np.ix_(b1, b2)], a[np.ix_(c1, c2)])
array([[ 4, 6],
[ 8, 10]])
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:为什么广播适用于整数,而不适用于布尔数组?这种行为有记录吗?还是我误解了一个更基本的问题?
正如@Divakar 在评论中指出的那样,布尔高级索引的行为就好像它们首先被馈入np.nonzero然后一起广播,请参阅相关文档以获得广泛的解释。引用文档,
通常,如果索引包含布尔数组,结果将与插入
obj.nonzero()相同位置并使用上述整数数组索引机制相同。x[ind_1, boolean_array, ind_2]相当于x[(ind_1,) + boolean_array.nonzero() + (ind_2,)]。
[...]
组合多个布尔索引数组或布尔索引数组与整数索引数组可以通过obj.nonzero()类比来最好地理解。该函数ix_还支持布尔数组,并且可以毫无意外地工作。
在您的情况下,广播不一定是问题,因为两个数组都只有两个非零元素。问题是结果中的维数:
>>> len(b1[:,None].nonzero())
2
>>> len(b2.nonzero())
1
Run Code Online (Sandbox Code Playgroud)
因此,索引表达式a[b1[:,None], b2]将等价于a[b1[:,None].nonzero() + b2.nonzero()],它会将长度为 3 的元组放入 中a,对应于 3d 数组索引。因此,您会看到“索引过多”的错误。
文档中提到的惊喜与您的示例非常接近:如果您没有注入该单例维度怎么办?从长度为 3 和长度为 4 的布尔数组开始,您最终会得到长度为 2 的高级索引,即 size 的一维数组(2,)。这永远不是您想要的,这将我们引向该主题的另一个琐事。
在计划改进高级索引方面进行了很多讨论,请参阅正在进行的NEP 21草案。问题的要点是 numpy 中的花哨索引虽然有明确记录,但具有一些非常古怪的功能,这些功能实际上对任何事情都没有用,但是如果您通过产生令人惊讶的结果而不是错误而犯了错误,这些功能会咬你。
NEP 的相关引述:
涉及多个数组索引的混合情况也令人惊讶,而且问题较少,因为当前的行为是如此无用,以至于在实践中很少遇到。当一个布尔数组索引与另一个布尔数组或整数数组混合时,布尔数组被转换为整数数组索引(相当于
np.nonzero())然后广播。例如,索引一个大小为(2, 2)like 的二维数组x[[True, False], [True, False]]会产生一个形状为 的一维向量(1,),而不是一个形状为 的二维子矩阵(1, 1)。
现在,我要强调的是,NEP 的工作正在进行中,但在 NEP 的当前状态下,建议之一是在上述高级索引情况下禁止使用布尔数组,而只允许在“外部索引”中使用它们。 " 场景,即究竟什么np.ix_可以帮助您处理布尔数组:
布尔索引在概念上是外部索引。以传统索引方式(即当前行为)与其他高级索引一起广播通常没有帮助或没有明确定义。因此,希望“非零”加广播行为的用户可以手动执行此操作。
我的观点是,在不久的将来,布尔高级索引的行为及其弃用状态(或缺乏)可能会发生变化。