我有一个矩阵M
,其中值为0到N
。我想展开此矩阵以创建一个新的矩阵A
,其中每个子矩阵A[i, :, :]
表示M == i。
以下解决方案使用循环。
# Example Setup
import numpy as np
np.random.seed(0)
N = 5
M = np.random.randint(0, N, size=(5,5))
# Solution with Loop
A = np.zeros((N, M.shape[0], M.shape[1]))
for i in range(N):
A[i, :, :] = M == i
这将产生:
M
array([[4, 0, 3, 3, 3],
[1, 3, 2, 4, 0],
[0, 4, 2, 1, 0],
[1, 1, 0, 1, 4],
[3, 0, 3, 0, 2]])
M.shape
# (5, 5)
A
array([[[0, 1, 0, 0, 0],
[0, 0, 0, 0, 1],
[1, 0, 0, 0, 1],
[0, 0, 1, 0, 0],
[0, 1, 0, 1, 0]],
...
[[1, 0, 0, 0, 0],
[0, 0, 0, 1, 0],
[0, 1, 0, 0, 0],
[0, 0, 0, 0, 1],
[0, 0, 0, 0, 0]]])
A.shape
# (5, 5, 5)
是否有更快的方法,或通过单次numpy操作完成此操作的方法?
答案 0 :(得分:6)
广播比较是您的朋友:
B = (M[None, :] == np.arange(N)[:, None, None]).view(np.int8)
np.array_equal(A, B)
# True
想法是扩大尺寸,以使比较可以以所需的方式进行广播。
@Alex Riley在评论中指出,您可以使用np.equal.outer
来避免自己做索引工作,
B = np.equal.outer(np.arange(N), M).view(np.int8)
np.array_equal(A, B)
# True
答案 1 :(得分:6)
您可以在此处使用一些广播:
P = np.arange(N)
Y = np.broadcast_to(P[:, None], M.shape)
T = np.equal(M, Y[:, None]).astype(int)
使用indices
的替代方法:
X, Y = np.indices(M.shape)
Z = np.equal(M, X[:, None]).astype(int)
答案 2 :(得分:3)
您可以像这样索引身份矩阵
A = np.identity(N, int)[:, M]
等等
A = np.identity(N, int)[M.T].T
或使用新的(v1.15.0)put_along_axis
A = np.zeros((N,5,5), int)
np.put_along_axis(A, M[None], 1, 0)
请注意,如果N远大于5,则创建NxN身份矩阵可能被认为是浪费的。我们可以使用跨步技巧缓解这种情况:
def read_only_identity(N, dtype=float):
z = np.zeros(2*N-1, dtype)
s, = z.strides
z[N-1] = 1
return np.lib.stride_tricks.as_strided(z[N-1:], (N, N), (-s, s))