我正在尝试编写一些使用逻辑numpy数组来索引更大数组的代码,类似于MATLAB允许使用逻辑数组进行数组索引的代码.
import numpy as np m = 4 n = 4 unCov = np.random.randint(10, size = (m,n) ) rowCov = np.zeros( m, dtype = bool ) colCov = np.ones( n, dtype = bool ) >>> unCov[rowCov, rowCov] [] # as expected >>> unCov[colCov, colCov] [0 8 3 3] # diagonal values of unCov, as expected >>> unCov[rowCov, colCov] ValueError: shape mismatch: objects cannot be broadcast to a single shape
对于最后的评估,我期望一个空数组,类似于MATLAB返回的数组.我不想在索引之前检查rowCov/colCov for True元素.为什么会这样,有没有更好的方法呢?
根据我的理解,numpy会将你的2d逻辑索引转换为实际的索引向量:arr[[True,False],[False,True]]
将成为arr[0,1]
一个ndarray
形状(2,2)
.但是,在最后一种情况下,第二个索引数组已满False
,因此它对应于长度为0的索引数组.这与另一个完整True
索引向量配对,对应于长度为4的索引数组.
从该numpy的手册:
如果索引数组的形状不同,则尝试将它们广播为相同的形状.如果它们无法广播到相同的形状,则会引发异常:
在您的情况下,错误正是由于这个原因:
--------------------------------------------------------------------------- IndexError Traceback (most recent call last)in () ----> 1 unCov[colCov,rowCov] IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (4,) (0,)
另一方面,如果索引数组沿任何给定维度为空,则MATLAB会自动返回一个空数组.
这实际上突出了MATLAB中的逻辑索引与numpy之间的根本区别.在MATLAB中,下标索引中的向量总是切出一个子数组.就是这两个
arr([1,2],[1,2])
和
arr([true,true],[true,true])
将返回2 x 2
矩阵的子矩阵arr
.如果逻辑索引向量短于数组的给定维度,则假定缺少索引元素false
.有趣的事实:索引向量也可以比给定的维度更长,只要多余的元素都是false
.所以上面也相当于
arr([true,true,false,false],[true,true])
和
arr([true,true,false,false,false,false,false],[true,true])
对于4 x 4
数组(为了参数).
然而,在numpy中,arrays
以这种方式使用布尔值numpy 进行索引将尝试提取向量.此外,布尔索引向量应与它们索引的维度长度相同.在你的4 x 4
例子中,
unCov[np.array([True,True]),np.array([True,True])]
和
unCov[np.array([True,True,False,False,False]),np.array([True,True,False,False,False])]
两者都返回两个第一对角元素,因此不是子矩阵而是向量.此外,他们还提出了不那么令人鼓舞的警告
/usr/bin/ipython:1: VisibleDeprecationWarning: boolean index did not match indexed array along dimension 0; dimension is 4 but corresponding boolean dimension is 5
因此,在numpy中,您的逻辑索引向量应该与相应的维度相同ndarray
.然后我上面写的内容是正确的:逻辑值被转换为索引,结果预期是一个向量.这个向量的长度是True
每个索引向量中元素的数量,所以如果你的布尔索引向量具有不同数量的True
元素,那么引用没有意义,并且你得到了你得到的错误.