我正在尝试编写一些使用逻辑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元素。为什么会发生这种情况,还有更好的方法吗?
答案 0 :(得分:5)
根据我的理解,numpy会将您的2d逻辑索引转换为实际索引向量:arr[[True,False],[False,True]]
对于arr[0,1]
形状ndarray
将变为(2,2)
。但是,在最后一种情况下,第二个索引数组是完整的False
,因此它对应于长度为0的索引数组。这与另一个完整的True
索引向量配对,对应于索引数组长度4。
如果索引数组的形状不同,则尝试进行 将它们播放到相同的形状。如果他们不能广播到 相同的形状,提出了一个例外:
在您的情况下,错误正是由此引起的:
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-1411-28e41e233472> in <module>()
----> 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
的{{1}}子矩阵。如果逻辑索引向量短于数组的给定维度,则假定缺失的索引元素为arr
。有趣的事实:只要多余的元素都是false
,索引向量也可以更长而不是给定的维度。所以上面也等同于
false
和
arr([true,true,false,false],[true,true])
表示arr([true,true,false,false,false,false,false],[true,true])
数组(为了参数)。
然而,在numpy中,以这种方式使用布尔值numpy 4 x 4
进行索引将尝试提取向量。此外,布尔索引向量应与它们索引的维度长度相同。在您的arrays
示例
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])]
因此,在numpy中,您的逻辑索引向量应与/usr/bin/ipython:1: VisibleDeprecationWarning: boolean index did not match indexed array along dimension 0; dimension is 4 but corresponding boolean dimension is 5
的相应维度的长度相同。然后我上面写的内容是正确的:逻辑值被转换为索引,结果预期是一个向量。这个向量的长度是每个索引向量中ndarray
元素的数量,所以如果你的布尔索引向量具有不同数量的True
元素,那么引用没有意义,你得到你得到的错误。