将2D数组复制到第三维,N次(Python)

时间:2015-08-23 21:51:14

标签: python arrays numpy

我想将一个numpy 2D数组复制到第三维。例如,如果我有这样一个(2D)numpy数组:

import numpy as np
arr = np.array([[1,2],[1,2]])

将其转换为3D矩阵,在新维度中包含N个此类副本,如N = 3:

np.array([[[1,2],[1,2]],[[1,2],[1,2]],[[1,2],[1,2]]])

6 个答案:

答案 0 :(得分:87)

可能最干净的方法是使用np.repeat

while True:
    A = raw_input('Enter A:')
    try:
         A = float(A)
    except ValueError:
         print "enter a float!"
    else:
         if A == 0:
             print "Enter not 0"
         else:
             break

话虽如此,您通常可以使用broadcasting完全避免重复数组。例如,我们想要添加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]] 向量:

(3,)

c = np.array([1, 2, 3]) 。我可以在第三维中复制a 3次的内容,然后在第一维和第二维中复制a两次的内容,这样我的两个数组都是c,然后计算他们的总和。但是,这样做更简单快捷:

(2, 2, 3)

此处,d = a[..., None] + c[None, None, :] 的形状为a[..., None](2, 2, 1)的形状为c[None, None, :] *。当我计算总和时,结果会被广播'沿着大小为1的尺寸,给我一个形状(1, 1, 3)的结果:

(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针对(2, 2, 1)数组的数组。这是因为如果其中一个阵列的尺寸小于另一个阵列,则只需要兼容两个阵列的尾随尺寸。举一个更复杂的例子:

(3,)

答案 1 :(得分:17)

另一种方法是使用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个切片。

答案 2 :(得分:3)

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

编辑@ Mr.F,以保留维度顺序:

B=B.T

答案 3 :(得分:3)

现在也可以使用np.tile如下实现:

import numpy as np

a = np.array([[1,2],[1,2]])
b = np.tile(a,(3, 1,1))

b.shape
(3,2,2)

b
array([[[1, 2],
        [1, 2]],

       [[1, 2],
        [1, 2]],

       [[1, 2],
        [1, 2]]])

答案 4 :(得分:2)

这是一个完全符合要求的广播示例。

b*a

然后(b*a)[:,:,0]是期​​望的结果,array([[1, 2],[1, 2]])生成a,这是原(b*a)[:,:,1].append()等等。

答案 5 :(得分:2)

使用视图并获得免费的运行时!将通用n-dim数组扩展到n+1-dim

NumPy 1.10.0中引入的方法,我们可以利用numpy.broadcast_to来简单地在3D输入数组中生成一个2D视图。好处将是没有额外的内存开销和几乎免费的运行时。这在数组很大且我们可以使用视图的情况下至关重要。此外,这将适用于一般n-dim情况。

我会用stack一词代替copy,因为读者可能会将它与创建内存副本的数组复制混淆。

沿第一个轴堆叠

如果我们要沿第一个轴堆叠输入arr,则用np.broadcast_to创建3D视图的解决方案是-

np.broadcast_to(arr,(3,)+arr.shape) # N = 3 here

沿第三个/最后一个轴堆叠

要沿第三轴堆叠输入arr,创建3D视图的解决方案是-

np.broadcast_to(arr[...,None],arr.shape+(3,))

如果我们实际上需要一个内存副本,则可以随时在其中附加.copy()。因此,解决方案将是-

np.broadcast_to(arr,(3,)+arr.shape).copy()
np.broadcast_to(arr[...,None],arr.shape+(3,)).copy()

这是两种情况下堆叠的工作方式,并显示了样品箱的形状信息-

# Create a sample input array of shape (4,5)
In [55]: arr = np.random.rand(4,5)

# Stack along first axis
In [56]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[56]: (3, 4, 5)

# Stack along third axis
In [57]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[57]: (4, 5, 3)

相同的解决方案可以将n-dim输入沿第一和最后一个轴扩展到n+1-dim视图输出。让我们探讨一些更暗淡的情况-

3D输入大小写:

In [58]: arr = np.random.rand(4,5,6)

# Stack along first axis
In [59]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[59]: (3, 4, 5, 6)

# Stack along last axis
In [60]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[60]: (4, 5, 6, 3)

4D输入大小写:

In [61]: arr = np.random.rand(4,5,6,7)

# Stack along first axis
In [62]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[62]: (3, 4, 5, 6, 7)

# Stack along last axis
In [63]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[63]: (4, 5, 6, 7, 3)

以此类推。

时间

让我们使用一个大样本2D案例,获取时间并验证输出为view

# Sample input array
In [19]: arr = np.random.rand(1000,1000)

让我们证明所提出的解决方案确实是一种观点。我们将沿第一个轴使用堆栈(沿第三个轴的结果非常相似)-

In [22]: np.shares_memory(arr, np.broadcast_to(arr,(3,)+arr.shape))
Out[22]: True

让我们了解一下它实际上是免费的-

In [20]: %timeit np.broadcast_to(arr,(3,)+arr.shape)
100000 loops, best of 3: 3.56 µs per loop

In [21]: %timeit np.broadcast_to(arr,(3000,)+arr.shape)
100000 loops, best of 3: 3.51 µs per loop

作为一个视图,将N3增加到3000不会改变计时,并且两者在计时单位上都可以忽略不计。因此,在内存和性能上都是高效的!