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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32171917/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 11:09:46  来源:igfitidea点击:

copy 2D array into 3rd dimension, N times (Python)

pythonarraysnumpy

提问by anon01

I'd like to copy a numpy 2D array into a third dimension. For example, given the (2D) numpy array:

我想将一个 numpy 二维数组复制到第三维中。例如,给定 (2D) numpy 数组:

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

convert it into a 3D matrix with N such copies in a new dimension. Acting on arrwith N=3, the output should be:

将其转换为在新维度中具有 N 个此类副本的 3D 矩阵。对arrN=3 进行操作,输出应为:

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

采纳答案by ali_m

Probably the cleanest way is to use np.repeat:

可能最干净的方法是使用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]]


Having said that, you can often avoid repeating your arrays altogether by using broadcasting. For example, let's say I wanted to add a (3,)vector:

话虽如此,您通常可以通过使用广播来避免完全重复数组。例如,假设我想添加一个(3,)向量:

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

to a. I could copy the contents of a3 times in the third dimension, then copy the contents of ctwice in both the first and second dimensions, so that both of my arrays were (2, 2, 3), then compute their sum. However, it's much simpler and quicker to do this:

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

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

Here, a[..., None]has shape (2, 2, 1)and c[None, None, :]has shape (1, 1, 3)*. When I compute the sum, the result gets 'broadcast' out along the dimensions of size 1, giving me a result of shape (2, 2, 3):

在这里,a[..., None]具有形状(2, 2, 1)并且c[None, None, :]具有形状(1, 1, 3)*。当我计算总和时,结果沿着大小 1 的维度“广播”出来,给我一个 shape 的结果(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]]

Broadcasting is a very powerful technique because it avoids the additional overhead involved in creating repeated copies of your input arrays in memory.

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



* Although I included them for clarity, the Noneindices into caren't actually necessary - you could also do a[..., None] + c, i.e. broadcast a (2, 2, 1)array against a (3,)array. This is because if one of the arrays has fewer dimensions than the other then only the trailingdimensions of the two arrays need to be compatible. To give a more complicated example:

* 虽然为了清楚起见我将它们包括在内,但实际上并不需要None索引c- 您也可以这样做a[..., None] + c,即(2, 2, 1)针对(3,)数组广播数组。这是因为如果其中一个数组的维度比另一个少,那么只有两个数组的尾随维度需要兼容。举一个更复杂的例子:

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

回答by rayryeng

Another way is to use numpy.dstack. Supposing that you want to repeat the matrix anum_repeatstimes:

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

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

The trick is to wrap the matrix ainto a list of a single element, then using the *operator to duplicate the elements in this list num_repeatstimes.

诀窍是将矩阵包装a成单个元素的列表,然后使用*运算符复制此列表中的元素num_repeats次数。

For example, if:

例如,如果:

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

This repeats the array of [1 2; 1 2]5 times in the third dimension. To verify (in IPython):

[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)

At the end we can see that the shape of the matrix is 2 x 2, with 5 slices in the third dimension.

最后我们可以看到矩阵的形状是2 x 2,在第三维有 5 个切片。

回答by yevgeniy

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

Edit @Mr.F, to preserve dimension order:

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

B=B.T

回答by Mike O'Connor

Here's a broadcasting example that does exactly what was requested.

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

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

Then b*ais the desired result and (b*a)[:,:,0]produces array([[1, 2],[1, 2]]), which is the original a, as does (b*a)[:,:,1], etc.

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

回答by Divakar

Use a view and get free runtime! Extend generic n-dimarrays to n+1-dim

使用视图并获得免费运行时间!将泛型n-dim数组扩展为n+1-dim

Introduced in NumPy 1.10.0, we can leverage numpy.broadcast_toto simply generate a 3Dview into the 2Dinput array. The benefit would be no extra memory overhead and virtually free runtime. This would be essential in cases where the arrays are big and we are okay to work with views. Also, this would work with generic n-dimcases.

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

I would use the word stackin place of copy, as readers might confuse it with the copying of arrays that creates memory copies.

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

Stack along first axis

沿第一轴堆叠

If we want to stack input arralong the first axis, the solution with np.broadcast_toto create 3Dview would be -

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

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

Stack along third/last axis

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

To stack input arralong the third axis, the solution to create 3Dview would be -

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

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

If we actually need a memory copy, we can always append .copy()there. Hence, the solutions would be -

如果我们真的需要一个内存副本,我们总是可以在.copy()那里追加。因此,解决方案将是 -

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

Here's how the stacking works for the two cases, shown with their shape information for a sample case -

以下是两种情况下堆叠的工作方式,显示了示例情况下的形状信息 -

# 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)

Same solution(s) would work to extend a n-diminput to n+1-dimview output along the first and last axes. Let's explore some higher dim cases -

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

3D input case :

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 input case :

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)

and so on.

等等。

Timings

时间安排

Let's use a large sample 2Dcase and get the timings and verify output being a view.

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

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

Let's prove that the proposed solution is a view indeed. We will use stacking along first axis (results would be very similar for stacking along the third axis) -

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

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

Let's get the timings to show that it's virtually free -

让我们看看时间来证明它实际上是免费的 -

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

Being a view, increasing Nfrom 3to 3000changed nothing on timings and both are negligible on timing units. Hence, efficient both on memory and performance!

作为一种观点,N3增加到3000在计时上没有任何改变,并且两者在计时单位上都可以忽略不计。因此,在内存和性能上都很有效!

回答by FBruzzesi

This can now also be achived using np.tileas follows:

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