2015-08-23 188 views

回答

34

也许最干净的方法是使用np.repeat

a = np.array([[1, 2], [1, 2]]) 
print(a.shape) 
# (2, 2) 

# indexing with np.newaxis inserts a new 3rd dimension, which we then repeat the 
# array along, (you can achieve the same effect by indexing with None, see below) 
b = np.repeat(a[:, :, np.newaxis], 3, axis=2) 

print(b.shape) 
# (2, 2, 3) 

print(b[:, :, 0]) 
# [[1 2] 
# [1 2]] 

print(b[:, :, 1]) 
# [[1 2] 
# [1 2]] 

print(b[:, :, 2]) 
# [[1 2] 
# [1 2]] 

说了这么多,你可以经常避免重蹈你的阵列总共使用broadcasting。例如,假设我想添加一个(3,)向量:

c = np.array([1, 2, 3]) 

a。我可以在第三维中复制a 3次的内容,然后在第一维和第二维中复制c的内容两次,以便我的两个数组都是(2, 2, 3),然后计算它们的总和。然而,这是更简单,更快地做到这一点:

d = a[..., None] + c[None, None, :] 

这里,a[..., None]具有形状(2, 2, 1)c[None, None, :]具有形状(1, 1, 3) *。当我计算总和,结果获得“广播”一起尺寸1的尺寸了,给我塑造(2, 2, 3)的结果:

print(d.shape) 
# (2, 2, 3) 

print(d[..., 0]) # a + c[0] 
# [[2 3] 
# [2 3]] 

print(d[..., 1]) # a + c[1] 
# [[3 4] 
# [3 4]] 

print(d[..., 2]) # a + c[2] 
# [[4 5] 
# [4 5]] 

广播是一个非常强大的技术,因为它避免了参与创建的额外开销在内存中重复输入数组的副本。


*虽然我包括他们清楚,None指数为c没有实际需要 - 你也可以做a[..., None] + c,即广播针对(3,)阵列(2, 2, 1)阵列。这是因为如果其中一个阵列的尺寸比另一个小,那么只有两个阵列的尺寸需要兼容。举一个更复杂的例子:

a = np.ones((6, 1, 4, 3, 1)) # 6 x 1 x 4 x 3 x 1 
b = np.ones((5, 1, 3, 2))  #  5 x 1 x 3 x 2 
result = a + b    # 6 x 5 x 4 x 3 x 2 
+0

要验证这确实给出正确的结果,也可以打印出来'b [:,:,0]','b [:,:,1]'和'b [:,:,2]'。每个第三维切片都是原始二维数组的副本。这只是看着'print(b)'而已。 – ely

+0

这是一个很好的答案!谢谢! – drg

11

另一种方法是使用numpy.dstack。假设你要重复的矩阵anum_repeats时间:

import numpy as np 
b = np.dstack([a]*num_repeats) 

诀窍是矩阵a包装成一个单一的元素的列表,然后使用*操作复制的元素在此列表中num_repeats倍。

例如,如果:

a = np.array([[1, 2], [1, 2]]) 
num_repeats = 5 

这重复的[1 2; 1 2] 5次在第三维阵列。为了验证(在IPython的):

In [110]: import numpy as np 

In [111]: num_repeats = 5 

In [112]: a = np.array([[1, 2], [1, 2]]) 

In [113]: b = np.dstack([a]*num_repeats) 

In [114]: b[:,:,0] 
Out[114]: 
array([[1, 2], 
     [1, 2]]) 

In [115]: b[:,:,1] 
Out[115]: 
array([[1, 2], 
     [1, 2]]) 

In [116]: b[:,:,2] 
Out[116]: 
array([[1, 2], 
     [1, 2]]) 

In [117]: b[:,:,3] 
Out[117]: 
array([[1, 2], 
     [1, 2]]) 

In [118]: b[:,:,4] 
Out[118]: 
array([[1, 2], 
     [1, 2]]) 

In [119]: b.shape 
Out[119]: (2, 2, 5) 

最后,我们可以看到,基体的形状是2 x 2,与在第三维5片。

+0

这与“重塑”相比如何?更快?给出相同的结构?它绝对整洁。 –

+0

@AnderBiguri我从来没有做过基准测试......我把它放在这里主要是为了完整。时间和看到差异会很有趣。 – rayryeng

+1

我只是做了img = np.dstack([arr] * 3)并且工作正常!谢谢 –

2
A=np.array([[1,2],[3,4]]) 
B=np.asarray([A]*N) 

编辑@ Mr.F,维护维序:

B=B.T 
+0

这导致我为N×2×2阵列,例如'B.shape'为'N'的任何值打印'(N,2,2)'。如果你用'B.T'转置'B',那么它匹配预期的输出。 – ely

+0

@ Mr.F - 你是对的。这将沿着第一维进行广播,所以'B [0],B [1],...'会给你正确的分片,我会争辩说,输入更容易,而不是使用'B [:,:,0],B [:,:,1]'等等。 – rayryeng

+0

键入起来可能更容易,但是例如,如果你用图像数据做这件事,它很可能是不正确的,因为几乎所有的算法都会期望线性代数的惯例被用于像素通道的2D切片。很难想象一个以2D数组开头的应用程序,按照一定的惯例处理行和列,然后想要将同一事物的多个副本扩展到新轴,但突然想要第一个轴将含义改为成为新的轴... – ely

1

这里有一个广播的例子,不被要求什么。

a = np.array([[1, 2], [1, 2]]) 
a=a[:,:,None] 
b=np.array([1]*5)[None,None,:] 

然后b*a是理想的结果和(b*a)[:,:,0]产生array([[1, 2],[1, 2]]),这是原来a一样,(b*a)[:,:,1]