ProgramingTip

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

bestdevel 2020. 10. 29. 08:26
반응형

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

그렇긴하지만, 브로드 캐스트 를 사용하여 어레이를 아예 반복하지 않는 경우가 . 예를 들어, (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.dstacka 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]등등

참고 URL : https://stackoverflow.com/questions/32171917/copy-2d-array-into-3rd-dimension-n-times-python

반응형