我想将numpy 2D数组复制到第三维。例如,如果我有这样的(2D)numpy的数组:将二维数组复制到第三维,N次(Python)
import numpy as np
arr = np.array([[1,2],[1,2]])
它转换成具有N个这样的拷贝的3D矩阵的新领域,像这样对N = 3:
np.array([[[1,2],[1,2]],[[1,2],[1,2]],[[1,2],[1,2]]])
我想将numpy 2D数组复制到第三维。例如,如果我有这样的(2D)numpy的数组:将二维数组复制到第三维,N次(Python)
import numpy as np
arr = np.array([[1,2],[1,2]])
它转换成具有N个这样的拷贝的3D矩阵的新领域,像这样对N = 3:
np.array([[[1,2],[1,2]],[[1,2],[1,2]],[[1,2],[1,2]]])
也许最干净的方法是使用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
另一种方法是使用numpy.dstack
。假设你要重复的矩阵a
num_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片。
这与“重塑”相比如何?更快?给出相同的结构?它绝对整洁。 –
@AnderBiguri我从来没有做过基准测试......我把它放在这里主要是为了完整。时间和看到差异会很有趣。 – rayryeng
我只是做了img = np.dstack([arr] * 3)并且工作正常!谢谢 –
A=np.array([[1,2],[3,4]])
B=np.asarray([A]*N)
编辑@ Mr.F,维护维序:
B=B.T
这导致我为N×2×2阵列,例如'B.shape'为'N'的任何值打印'(N,2,2)'。如果你用'B.T'转置'B',那么它匹配预期的输出。 – ely
@ Mr.F - 你是对的。这将沿着第一维进行广播,所以'B [0],B [1],...'会给你正确的分片,我会争辩说,输入更容易,而不是使用'B [:,:,0],B [:,:,1]'等等。 – rayryeng
键入起来可能更容易,但是例如,如果你用图像数据做这件事,它很可能是不正确的,因为几乎所有的算法都会期望线性代数的惯例被用于像素通道的2D切片。很难想象一个以2D数组开头的应用程序,按照一定的惯例处理行和列,然后想要将同一事物的多个副本扩展到新轴,但突然想要第一个轴将含义改为成为新的轴... – ely
这里有一个广播的例子,不被要求什么。
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]
等
要验证这确实给出正确的结果,也可以打印出来'b [:,:,0]','b [:,:,1]'和'b [:,:,2]'。每个第三维切片都是原始二维数组的副本。这只是看着'print(b)'而已。 – ely
这是一个很好的答案!谢谢! – drg