답변:
아마도 가장 깨끗한 방법은 다음을 사용하는 것입니다 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
np.newaxis
단지 별칭None
또 다른 방법은 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
됩니까? 더 빨리? 동일한 구조를 제공합니까? 확실히 깔끔합니다.
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-dim
을 n+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
B.shape
지문 (N, 2, 2)
의 어떤 값에 대해 N
. 당신이 트랜스 경우 B
에 B.T
그것은 예상 출력과 일치합니다.
B[0], B[1],...
당신에게 내가 주장하는 것 올바른 슬라이스를 줄 것이다 그의 더 쉽게 입력하는 대신 사용하는 말 B[:,:,0], B[:,:,1]
등
B[:,:,i]
내가 익숙한 것뿐만 아니라 그것을 선호합니다 .
b[:,:,0]
,b[:,:,1]
하고b[:,:,2]
. 각 3 차원 슬라이스는 원본 2D 배열의 복사본입니다. 이것은 단지를 보는 것만 큼 분명하지 않습니다print(b)
.