본문 바로가기
파이썬/Numpy(넘파이)

[NumPy] 5. 넘파이 브로드캐스팅, 배열 인덱싱, 불 인덱싱

by 쿠킷리스트 2021. 10. 15.

학습내용

#1 : 넘파이 브로드캐스팅(Broadcasting rules)
#2 : 넘파이 인덱싱(Advanced Indexing and index tricks)동
#3 : Bool로 인덱싱하기(Indexing with Boolean Arrays)
#4 : ix_() function

#1 : 넘파이 브로드캐스팅(Broadcasting rules)

 브로드캐스팅은 단순하게 편리성을 위해 shape(차원 혹은 다른 행과 열)이 다른 np.array끼리 연산을 지원해준다. 차원(ndim)이 같고 각 축(axis)의 값이 같거나 1일 때만 기본적으로 연산이 가능하지만 브로드캐스팅을 통해 행과 열의 개수가 다르더라고 계산할 수 있다. 연산시 부족한 행과 열의 추가(자기 자신을 복제)되어 연산이 가능하도록 만들어준다.

import numpy as np
np.ones((3,4))
# array([[1., 1., 1., 1.],
#        [1., 1., 1., 1.],
#        [1., 1., 1., 1.]])
np.arange(4)
# array([0, 1, 2, 3])

np.ones((3,4)) * np.arange(4)
# array([[0., 1., 2., 3.],
#        [0., 1., 2., 3.],
#        [0., 1., 2., 3.]])

np.arange(3).reshape(3,1) * np.arange(3)

#2 : 인덱스 배열로 인덱싱하기(Indexing with Arrays of Indices)

 인덱스를 가진 배열로 인덱싱을 할 수 있다. 배열로 인덱싱을 하면 배열의 각 값에 따라 인덱싱 값을 구할 수 있다. 배열로 인덱싱을 할 경우 인덱싱을 하고있는 배열의 차원이 유지된다.

a = np.arange(12)**2
a
# array([  0,   1,   4,   9,  16,  25,  36,  49,  64,  81, 100, 121])
#인덱스    0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11
i = np.array([1,1,3,8,5])
a[i]
# array([ 1,  1,  9, 64, 25])
j = np.array([[3,4],[9,7]])
a[j]
# array([[ 9, 16],
#        [81, 49]])

2) 인덱싱 코드 예시

palette = np.array([[0, 0, 0],          # black
                    [255, 0, 0],        # red
                    [0, 255, 0],        # green
                    [0, 0, 255],        # blue
                    [255, 255, 255]])   # white
image = np.array([[0, 1, 2, 0],
                  [0, 3, 4, 0]])

palette[image]
# array([[[  0,   0,   0],
#         [255,   0,   0],
#         [  0, 255,   0],
#         [  0,   0,   0]],

#        [[  0,   0,   0],
#         [  0,   0, 255],
#         [255, 255, 255],
#         [  0,   0,   0]]])

- 위 코드에서 image에서 ([[0, 1, 2, 0], [0, 3, 4, 0]])은 2차원이기에 열 값을 가져오는 것이 아니라 행 값을 가져온다. 따라서, [0, 1, 2, 0]은 2차원 배열 안에서 1행, 2행, 3행, 1행을 가져오고, [0, 3, 4, 0]은 2차원 배열 안에서 1행, 4행, 5행, 1행을 가져온다.

- 행을 가져왔기 때문에 2차원에서 3차원으로 바뀌게 된다.

 

time = np.linspace(20, 145, 5)
time
# array([ 20.  ,  51.25,  82.5 , 113.75, 145.  ])
data = np.sin(np.arange(20)).reshape(5,4)
data
# array([[ 0.        ,  0.84147098,  0.90929743,  0.14112001],
#        [-0.7568025 , -0.95892427, -0.2794155 ,  0.6569866 ],
#        [ 0.98935825,  0.41211849, -0.54402111, -0.99999021],
#        [-0.53657292,  0.42016704,  0.99060736,  0.65028784],
#        [-0.28790332, -0.96139749, -0.75098725,  0.14987721]])

ind = data.argmax(axis=0) #행 기준 가장 높은 값을 가지고 있는 인덱스
ind
# array([2, 0, 3, 1])
time_max = time[ind]
time_max
# array([ 82.5 ,  20.  , 113.75,  51.25])
data_max = data[ind, range(data.shape[1])] #ind는 행, range는 열에 접근하는 것
data_max
# array([0.98935825, 0.84147098, 0.99060736, 0.6569866 ])
np.all(data_max == data.max(axis=0)) #all함수는 모든 값이 참이면 True 반환
# True

- data_max는 data의 2,0 / 0,1 / 3,2 / 1,3의 값을 가져온다.

- shape[1]은 전체 열 개수를 반환하며, shpae[0]은 전체 행을 반환한다.

- 위 코드에서 range(data.shape[1])는 range(4)를 의미한다.


#3 : Bool로 인덱싱하기(Indexing with Boolean Arrays)

 Bool 타입을 가진 값들로도 인덱싱이 가능하다. 원하는 값만 남기거나 변환할 때 유용하다. 구조를 잘 기억할 것.

a = np.arange(12).reshape(3, 4)
a
# array([[ 0,  1,  2,  3],
#        [ 4,  5,  6,  7],
#        [ 8,  9, 10, 11]])
b = a > 4
b
# array([[False, False, False, False],
#        [False,  True,  True,  True],
#        [ True,  True,  True,  True]])

#불타입으로 인덱싱 True 값에 대응하는 것만 반환
a[b]
# array([ 5,  6,  7,  8,  9, 10, 11])

#True 값을 모두 0으로 바꿔준다
a[b] = 0
a
# array([[0, 1, 2, 3],
#        [4, 0, 0, 0],
#        [0, 0, 0, 0]])

#4 : ix_() function

 .ix_() 을 통해 서로 다른 shape(차원 혹은 다른 행과 열)을 가진 배열들을 묶어서 처리할 수 있다.

a = np.array([2,3,4,5])
b = np.array([8,5,4])
c = np.array([5,4,6,8,3])
ax, bx, cx = np.ix_(a,b,c)
ax
# array([[[2]],

#        [[3]],

#        [[4]],

#        [[5]]])
bx
# array([[[8],
#         [5],
#         [4]]])
cx
# array([[[5, 4, 6, 8, 3]]])

ax.shape, bx.shape, cx.shape
# ((4, 1, 1), (1, 3, 1), (1, 1, 5))

result = ax + bx * cx
result
# array([[[42, 34, 50, 66, 26],
#         [27, 22, 32, 42, 17],
#         [22, 18, 26, 34, 14]],

#        [[43, 35, 51, 67, 27],
#         [28, 23, 33, 43, 18],
#         [23, 19, 27, 35, 15]],

#        [[44, 36, 52, 68, 28],
#         [29, 24, 34, 44, 19],
#         [24, 20, 28, 36, 16]],

#        [[45, 37, 53, 69, 29],
#         [30, 25, 35, 45, 20],
#         [25, 21, 29, 37, 17]]])

result[3, 2, 4] #3차원에서 4행, 2차원 3행, 5열
# 17
a[3] + b[2] *c[4]
# 17

댓글