使用Numpy中的逻辑索引获取矩阵的网格

6

我正在尝试使用numpy重写一个最初在MATLAB中的函数,其中有一个逻辑索引部分,代码如下:

X = reshape(1:16, 4, 4).';
idx = [true, false, false, true];
X(idx, idx)

ans =

     1     4
    13    16

当我尝试在numpy中实现时,无法获得正确的索引:

X = np.arange(1, 17).reshape(4, 4)
idx = [True, False, False, True] 
X[idx, idx]
# Output: array([6, 1, 1, 6])

如何通过逻辑索引从矩阵中获取网格?


我注意到可以通过 X[idx,:][:,idx] 来实现,但这不奇怪吗? - petrichor
3个回答

7

您还可以写成:

>>> X[np.ix_(idx,idx)]
array([[ 1,  4],
       [13, 16]])

+1;不知道np.ix_。然而,这种方法的性能比"常规索引"差(2倍)。 - root
1
@root:这与您的方法不同,因为它允许修改切片矩阵,而您的方法只允许只读访问:http://wiki.scipy.org/NumPy_for_Matlab_Users#head-13d7391dd7e2c57d293809cff080260b46d8e664 - Amro
真的,没错。你可能想在你的回答中加上这个。 - root
不知怎么的,我看不出这两种方法之间的区别,你能举个例子说明一下吗? - Akavall
2
@Akavall -- Amro的支持赋值,而我的更快;因此它们有不同的用例。这就是为什么X[np.ix_(idx, idx)]=np.zeros((2,2))会修改原始数组,但X[idx][:,idx]=np.zeros((2,2))不会的原因。 - root

4
In [1]: X = np.arange(1, 17).reshape(4, 4)

In [2]: idx = np.array([True, False, False, True])  # note that here idx has to
                                                    # be an array (not a list)
                                                    # or boolean values will be 
                                                    # interpreted as integers

In [3]: X[idx][:,idx]
Out[3]: 
array([[ 1,  4],
       [13, 16]])

+1 我不知道将 idx 列表转换为数组会允许使用 x[idx] 进行正确的索引。 - Saullo G. P. Castro

2
numpy中,这被称为fancy indexing。要获取所需的项目,您应该使用一个索引的2D数组。
您可以使用outer将您的一维idx转换为适当的2D索引数组。当应用于两个1D序列时,outers会将一个序列的每个元素与另一个序列的每个元素进行比较。回想一下,True*True=TrueFalse*True=Falsenp.multiply.outer()(与np.outer()相同)可以给您2D索引:
idx_2D = np.outer(idx,idx)
#array([[ True, False, False,  True],
#       [False, False, False, False],
#       [False, False, False, False],
#       [ True, False, False,  True]], dtype=bool)

您可以使用以下内容:

x[ idx_2D ]
array([ 1,  4, 13, 16])

在您的实际代码中,您可以使用x=[np.outer(idx,idx)],但这不会节省内存,与在切片后包含del idx_2D相同。


2
不将中间数组分配给变量并不会节省任何内存:它会被创建、使用,然后丢弃。这与在索引后编写 del idx_2D 的情况相同。 - Jaime

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