numpy 如何将一个2D数组复制到一个3rd维,N次?

zazmityj  于 12个月前  发布在  其他
关注(0)|答案(7)|浏览(100)

我想把一个二维数组复制到三维空间。例如,给定2D numpy数组:

import numpy as np

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

将其转换为在新维度中具有N个这样的副本的3D矩阵。使用N=3作用于arr,输出应为:

new_arr[:,:,0]
# array([[1, 2], [1, 2]])

new_arr[:,:,1]
# array([[1, 2], [1, 2]])

new_arr[:,:,2]
# array([[1, 2], [1, 2]])

# new_arr.shape = (2, 2, 3)
8gsdolmq

8gsdolmq1#

最简单的方法可能是使用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)阵列。这是因为如果其中一个数组的维数比另一个少,那么两个数组的 trailing 维需要兼容。给予一个更复杂的例子:
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
rkue9o1l

rkue9o1l2#

另一种方法是使用numpy.dstack。假设你想重复矩阵anum_repeats次:

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

技巧是将矩阵a Package 成一个单一元素的列表,然后使用*运算符将该列表中的元素复制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个切片。

n3ipq98p

n3ipq98p3#

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

在NumPy 1.10.0中引入,我们可以利用numpy.broadcast_to简单地在2D输入数组中生成3D视图。好处是没有额外的内存开销和几乎免费的运行时。这在数组很大并且我们可以使用视图的情况下是必不可少的。此外,这将适用于一般的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在时序上没有任何变化,两者在时序单位上都可以忽略不计。因此,高效的内存和性能!

vktxenjb

vktxenjb4#

现在也可以使用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]]])
xmq68pz9

xmq68pz95#

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

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

B=B.T
wz1wpwve

wz1wpwve6#

下面是一个广播示例,它完全按照要求执行。

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]也是如此,等等。

mrwjdhj3

mrwjdhj37#

总结上述解决方案:

a = np.arange(9).reshape(3,-1)
b = np.repeat(a[:, :, np.newaxis], 5, axis=2)
c = np.dstack([a]*5)
d = np.tile(a, [5,1,1])
e = np.array([a]*5)
f = np.repeat(a[np.newaxis, :, :], 5, axis=0) # np.repeat again
print('b='+ str(b.shape), b[:,:,-1].tolist())
print('c='+ str(c.shape),c[:,:,-1].tolist())
print('d='+ str(d.shape),d[-1,:,:].tolist())
print('e='+ str(e.shape),e[-1,:,:].tolist())
print('f='+ str(f.shape),f[-1,:,:].tolist())

b=(3, 3, 5) [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
c=(3, 3, 5) [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
d=(5, 3, 3) [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
e=(5, 3, 3) [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
f=(5, 3, 3) [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

好运

相关问题