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


106

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)

답변:


146

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

이것은 참으로 올바른 결과를 제공하는지 확인하려면, 당신은 또한 인쇄 할 수 있습니다 b[:,:,0], b[:,:,1]하고 b[:,:,2]. 각 3 차원 슬라이스는 원본 2D 배열의 복사본입니다. 이것은 단지를 보는 것만 큼 분명하지 않습니다 print(b).
ely

None과 np.newaxis의 차이점은 무엇입니까? 내가 테스트했을 때 동일한 결과를 얻었습니다.
monolith

1
- 그들은 정확히 동일 @wedran np.newaxis단지 별칭None
ali_m가

27

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


이것은 어떻게 비교 reshape됩니까? 더 빨리? 동일한 구조를 제공합니까? 확실히 깔끔합니다.
안 데르 Biguri

@AnderBiguri 나는 벤치마킹 한 적이 없습니다 ... 나는 주로 완전성을 위해 이것을 여기에 넣었습니다. 시간을 내고 차이점을 보는 것은 흥미로울 것입니다.
rayryeng

1
방금 img = np.dstack ([arr] * 3)했고 잘 작동했습니다! 감사합니다
thanos.a 2017

1
효율성을 위해 본 결과를 제안 할 수 있다고 생각했습니다. 오래된 게시물이기 때문에 사람들은 그것을 놓쳤을 것입니다. 이 Q & A에 대한 솔루션을 추가했습니다.
Divakar

1
IMHO에서 가장 읽기 쉬운 솔루션이지만 다른 비교 방법과 비교하여 벤치마킹하는 것이 좋습니다.
mrgloom

16

보기를 사용하고 무료 런타임을 받으세요! 일반 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타이밍에 변경 아무것도 둘 타이밍 단위에 무시할 수 있습니다. 따라서 메모리와 성능 모두 효율적입니다!


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

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

B=B.T

는 N이 결과, 저 예 2 × 2 배열을 X B.shape지문 (N, 2, 2)의 어떤 값에 대해 N. 당신이 트랜스 경우 BB.T그것은 예상 출력과 일치합니다.
ely

@ Mr.F-맞아요. 이것은 첫 번째 차원 함께 방송하고, 그렇게 할 것이다 B[0], B[1],...당신에게 내가 주장하는 것 올바른 슬라이스를 줄 것이다 그의 더 쉽게 입력하는 대신 사용하는 말 B[:,:,0], B[:,:,1]
rayryeng

입력하는 것이 더 쉬울 수 있지만, 예를 들어 이미지 데이터로이 작업을 수행하는 경우 거의 모든 알고리즘이 픽셀 채널의 2D 슬라이스에 사용되는 선형 대수의 규칙을 예상하기 때문에 대부분 부정확 할 수 있습니다. 2D 배열로 시작하여 특정 규칙에 따라 행과 열을 처리 한 다음 동일한 항목의 여러 복사본을 새 축으로 확장하려는 응용 프로그램을 상상하기 어렵지만 갑자기 첫 번째 축의 의미를 다음과 같이 변경하려는 경우 새로운 축이
되십시오

@ Mr.F-오 물론입니다. 앞으로 3D 매트릭스를 사용할 응용 프로그램이 무엇인지 짐작할 수 없습니다. 즉, 모든 것은 응용 프로그램에 따라 다릅니다. FWIW, 나는 B[:,:,i]내가 익숙한 것뿐만 아니라 그것을 선호합니다 .
rayryeng

2

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

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


2

이제 다음과 같이 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]]])
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.