布尔索引但实为其他操作

2 投票
1 回答
1358 浏览
提问于 2025-04-18 11:02

我在尝试做布尔索引,但遇到了一些问题。

np.random.randn(8).reshape((4,2))
Out[11]: 
array([[-1.13058416,  1.08397186],
       [-1.2730122 ,  0.78306498],
       [-0.05370502, -1.16723298],
       [ 1.01750955, -0.95029671]])

a=np.random.randn(8).reshape((4,2))

a[[2==3,3==0,0==0,1!=1]]
Out[13]: 
array([[ 0.18235299, -2.53482367],
       [ 0.18235299, -2.53482367],
       [-1.03752809, -2.2790847 ],
       [ 0.18235299, -2.53482367]])

这到底发生了什么?我原本想的是布尔索引。这个操作是什么?我并不是在问怎么把这个改成布尔索引,而是想知道这个操作到底在干嘛?这样做可以吗?

1 个回答

2

可以把 ndarray 想象成升级版的 list。在数组上进行的广播和操作会自动扩展到参与这些操作的列表上,所以你可以把一个数组和一个形状兼容的列表相加,而 numpy 不会试图把它们合并在一起(就像它会对两个列表那样做)。

有一个很大的(对我来说也很困惑的)例外情况就是花式索引。花式索引本身就让我感到困惑(因为我之前用的是 MATLAB),因为下面这两个操作的结果却不一样,这让我觉得很奇怪:

import numpy as np
A = np.random.rand(3,3)
A[0:1,0:1]
A[range(2),range(2)]

前者是一个切片操作,返回一个 2x2 的子矩阵。而后者是花式索引的例子,只返回一个包含 A[0,0]A[1,1] 的 2 元素数组。

你的问题和另一个同样奇怪的情况有关:在花式索引中,布尔值的列表和数组表现得不一样。考虑下面这两个例子,和你的问题类似:

A = np.random.rand(4,2)
bool_index_list = [False, True, True, False]
bool_index_array = np.array(bool_index_list)
A[bool_index_list].shape
A[bool_index_array].shape

前者返回 (4,2),而后者返回 (2,2)

在前面的例子中,由于索引是一个 list,布尔值会被转换成对应的整数,结果 [0,1,1,0] 被用作矩阵中的实际索引,分别返回 [第一行, 第二行, 第二行, 第一行]。

在后面的例子中,dtype=bool 的索引 array 按照你预期的方式使用:它作为一个掩码,忽略那些索引为 FalseA 的行。

numpy 的发布说明中提到,

将来,布尔数组(比如 Python 布尔值的列表)将始终被视为布尔索引,而布尔标量(包括 Python 的 True)将是合法的 布尔 索引。

因此,上面基于列表的索引在 numpy 1.10.1 中给我带来了以下警告:

FutureWarning: 在未来,布尔数组将被视为布尔数组索引

所以简单来说,你的问题是合法的,但这种情况不会持续太久。最好还是使用 ndarray 的花式索引,这样你就不会遇到麻烦了。

撰写回答