[python] 2D 배열을 3 차원으로 N 번 복사 (Python)

numpy 2D 배열을 3 차원으로 복사하고 싶습니다. 예를 들어, (2D) numpy 배열이 주어지면 :

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

새로운 차원에서 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)



답변

아마도 가장 깨끗한 방법은 다음을 사용하는 것입니다 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]]

그렇긴하지만, broadcast 를 사용하여 어레이를 아예 반복하지 않는 경우가 많습니다 . 예를 들어, (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. 즉, (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


답변

또 다른 방법은 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]3 차원에서 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이 3 차원에 5 개의 슬라이스가있는 것을 볼 수 있습니다 .


답변

보기를 사용하고 무료 런타임을 받으세요! 일반 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-dimn+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

, 뷰 인 증가 N에서 3까지 3000타이밍에 변경 아무것도 둘 타이밍 단위에 무시할 수 있습니다. 따라서 메모리와 성능 모두 효율적입니다!


답변

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

@ Mr.F를 편집하여 차원 순서를 유지합니다.

B=B.T


답변

다음은 요청 된 내용을 정확히 수행하는 방송 예제입니다.

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].


답변

이제 다음과 같이 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]]])


답변