处理三维矩阵时," M"对于尺寸(A,B,C),可以使用2个向量X来索引M,其中元素在[0,A)中,Y在[0,B]中具有相同维度D的元素。
更具体地说,我明白在写作时
M[X,Y,:]
我们正在为每个"我"在D,
M[X[i], Y[i], :],
因此最终产生DxC矩阵。
现在假设
X is a numpy array of dim U, same concept as before
this time Y is a matrix UxL, where each row correspond to a Boolean numpy array
(a mask)
并查看以下代码
for u in U:
my_matrix[Y[u], X[u], :] += 1 # Y[u] is the mask that selects specific elements of the first dimension
我想在没有for循环的情况下编写相同的代码。这样的东西
np.add.at(my_matrix, (Y, X), 1) # i use numpy.ufunc.at since same elements could occur multiple times in X or Y.
遗憾地返回以下错误
IndexError:布尔索引与维度0的索引数组不匹配; dimension是L但相应的布尔维数是1
执行作业
时也可以找到此问题for u in U:
a_matrix[u, Y[u], :] = my_matrix[Y[u], X[u], :]
你知道如何以优雅的方式解决这个问题吗?
答案 0 :(得分:0)
简单地使用通常的nd-array形状的花式索引的简单方法不太适用于您的问题。这就是为什么我这样说:Y
有布尔行,告诉你哪些索引沿着第一个维度。因此,Y[0]
和Y[1]
可能会有不同数量的True
元素,因此Y
行将沿第一维切片不同长度的子数组。换句话说,您的阵列形索引不能转换为矩形子阵列。
但是如果你考虑一下你的索引数组意味着什么,那么就有了出路。 Y
行确切地告诉您要修改哪些元素。如果我们将所有索引混淆为大量的1d花式索引,我们可以精确定位我们想要索引的第一维上的每个(x,y)
点。
特别是,请考虑以下示例(顺便说一句,你的问题中很少遗漏):
A = np.arange(4*3*2).reshape(4,3,2)
Y = np.array([[True,False,False,True],
[True,True,True,False],
[True,False,False,True]])
X = np.array([2,1,2])
A
是形状(4,3,2)
,Y
是形状(3,4)
(并且第一行和最后一行有意义相同),X
是形状(3 ,)`(并且第一个和最后一个元素的目的是相同的)。让我们将布尔索引转换为线性索引的集合:
U,inds = Y.nonzero()
#U: array([0, 0, 1, 1, 1, 2, 2])
#inds: array([0, 3, 0, 1, 2, 0, 3])
如您所见,U
是True
中每个Y
元素的行索引。这些是给出Y
行和X
元素之间对应关系的索引。第二个数组inds
是沿第一维的实际线性索引(对于给定的行)。
我们差不多完成了,我们所需要的只是将inds
的元素与X
的相应索引配对作为第二维。这实际上非常简单:我们只需要使用X
索引U
。
总而言之,以下两个是针对同一问题的等效循环和花式索引解决方案:
B = A.copy()
for u in range(X.size):
A[Y[u],X[u],:] += 1
U,inds = Y.nonzero()
np.add.at(B,(inds,X[U]),1)
A
使用循环进行修改,使用B
修改np.add.at
。我们可以看到两者是平等的:
>>> (A == B).all()
True
如果你看看这个例子,你可以看到我有意复制了第一和第三组索引。这表明np.add.at
正在使用这些花哨的索引,并且累积了在输入上多次出现的索引。 (打印B
并与A
的初始值进行比较,您可以看到最后一项递增两次。)