이번 포스팅에서는 A, B 두개의 값이 들어있는 배열과 위치를 지정해둔 idx 배열이 있다고 했을 때, A배열의 idx 배열 내 index 위치에다가 B배열의 원소를 순서대로 더하기하는 두가지 방법을 소개하겠습니다. 


(방법 1) for loop 으로 A배열의 idx 위치에 B배열의 원소 순서대로 더하기

(방법 2) np.add.at(A, idx, B) 메소드로 A배열의 idx 위치에 B배열의 원소 순서대로 더하기


for loop을 이용한 (방법 1)은 numpy의 add.at() 함수를 몰라도 어렵지 않게 구현할 수 있고 또 코드를 해석하기도 편한 장점이 있습니다만, 만약 더해야 하는 원소의 개수가 많아지면 for loop 연산을 하는데 시간이 많이 소요되는 단점이 있습니다. 


numpy의 add.at() 메소드를 사용하는 (방법 2)는 Vectorization 연산을 하여 한꺼번에 두 배열 간 idx 위치에 맞게 더하기 연산을 수행하므로 위의 for loop 방법 1 대비 빠르다는 장점이 있습니다. (더해야 하는 원소 개수가 작으면 방법1과 방법2의 속도 차이를 느끼기 힘든데요, 만약 몇 몇 백만개라면 for loop으로 수 분~ 수 시간 걸릴 것이 numpy.add.at() 메소드로는 수 초안에 끝낼 수도 있을만큼 성능 차이가 많이 날 것입니다. (대신 numpy.add.at() 함수를 기억하고 사용법도 알고 있어야 하겠지만요.)





  (방법 1) for loop 으로 A배열의 idx 위치에 B배열의 원소 순서대로 더하기


먼저, 예제로 사용할 A배열, B배열, idx 배열을 만들어보겠습니다. 



import numpy as np


A = np.arange(24).reshape(8, 3)

print(A)

[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]
 [12 13 14]
 [15 16 17]
 [18 19 20]
 [21 22 23]]


B = np.arange(12).reshape(4, 3)

print(B)

[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]


idx = np.array([0, 0, 3, 5])




자, 이제 준비가 되었으니 for loop 문과 enumerate() 함수를 사용하여 A배열의 idx 배열 내 숫자의 위치에다가 B배열의 원소를 순서대로 더해보겠습니다. 

idx 가 array([0, 0, 2, 5]) 이므로 A배열의 1차원의 idx([0, 0, 3, 5]) 번째 위치(0, 0, 3, 5)의 원소에 B배열의 0, 1, 2, 3 번째 위치의 원소를 더하는 연산을 수행하게 됩니다. 


말로만 설명을 들으면 좀 헷갈리고 이해가 잘 안갈수도 있는데요, 아래에 배열 덧셈 연산식과 연산이 끝난 A배열에서 결과값이 바뀐 0, 2, 5 번째 원소를 빨간색으로 표시해두었으니 참고하기 바랍니다. (* idx([0, 0, 3, 5]) 에서 A[0]에 B[0]과 B[1]이 각 각 더해지는 것에 주의)


array A at idx([0])  + array B[0]          = array A[0]

array([0, 1, 2])        + array([0, 1, 2])    = array([0, 2, 4])


array A at idx([0])  + array B[1         = array A[0]

array([0, 2, 4])      + array([3, 4, 5])     = array([3, 6, 9])


array A at idx([3])  + array B[2]          = array A[3]

array([9, 10, 11])     + array([6, 7, 8])    = array([15, 17, 19])


array A at idx([5])  + array B[3]          = array A[5]

array([15, 16, 17])   + array([9, 10, 11])  = array([24, 25, 26])



for i, id in enumerate(idx):

    A[id] += B[i]


print(A)

[[ 3  6  9]
 [ 3  4  5]
 [ 6  7  8]
 [15 17 19]
 [12 13 14]
 [24 26 28]
 [18 19 20]
 [21 22 23]]

 




  (방법 2) np.add.at(A, idx, B) 함수로 A배열의 idx 위치에 B배열의 원소 순서대로 더하기


위의 for loop을 이용한 (방법 1)과 똑같은 연산을 numpy의 add.at(A, idx, B) 메소드를 이용해서 수행하면 아래와 같습니다. 코드도 깔끔하고 연산속도도 더 빠르므로 특히 대용량 배열을 다루어야 하는 경우라면 알아두면 좋겠습니다. 



import numpy as np


A = np.arange(24).reshape(8, 3)

B = np.arange(12).reshape(4, 3)

idx = np.array([0, 0, 3, 5])


np.add.at(A, idx, B)


print(A)

[[ 3  6  9]
 [ 3  4  5]
 [ 6  7  8]
 [15 17 19]
 [12 13 14]
 [24 26 28]
 [18 19 20]
 [21 22 23]]

 



많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. ^_^


Posted by R Friend Rfriend

댓글을 달아 주세요