将 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
copy 2D array into 3rd dimension, N times (Python)
提问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 arr
with N=3, the output should be:
将其转换为在新维度中具有 N 个此类副本的 3D 矩阵。对arr
N=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 a
3 times in the third dimension, then copy the contents of c
twice 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 None
indices into c
aren'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 a
num_repeats
times:
另一种方法是使用numpy.dstack
. 假设您要重复矩阵a
num_repeats
时间:
import numpy as np
b = np.dstack([a]*num_repeats)
The trick is to wrap the matrix a
into a list of a single element, then using the *
operator to duplicate the elements in this list num_repeats
times.
诀窍是将矩阵包装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*a
is 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-dim
arrays to n+1-dim
使用视图并获得免费运行时间!将泛型n-dim
数组扩展为n+1-dim
Introduced in NumPy 1.10.0
, we can leverage numpy.broadcast_to
to simply generate a 3D
view into the 2D
input 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-dim
cases.
在NumPy 中1.10.0
引入,我们可以利用numpy.broadcast_to
简单地3D
在2D
输入数组中生成一个视图。好处是没有额外的内存开销和几乎免费的运行时间。在数组很大并且我们可以使用视图的情况下,这将是必不可少的。此外,这适用于一般n-dim
情况。
I would use the word stack
in 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 arr
along the first axis, the solution with np.broadcast_to
to create 3D
view 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 arr
along the third axis, the solution to create 3D
view 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-dim
input to n+1-dim
view 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 2D
case 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 N
from 3
to 3000
changed nothing on timings and both are negligible on timing units. Hence, efficient both on memory and performance!
作为一种观点,N
从3
增加到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]]])