지금까지는 int ndarray를 통해서만 인덱싱을 해보았습니다.
하지만 넘파이에선 int ndarray이외에도 bool ndarray인덱싱도 가능합니다.
자세한건 코드를 통해 확인해보시죠!
bool ndarray 기본형
import numpy as np
a = np.arange(5)
print(f"ndarray: \n{a}")
b_indices = np.array([True, False, True, False, True]) # indices는 a shape과 같아야한다.
print(f"a[b_indices]: \n{a[b_indices]}")
output :
코드를 보시면 감이 오시겠지만 b_indices를 True와 False 로 이루어진 boolean 형태의 array로 만듭니다..
이때 b_indcies의 shape은 값을 가져올 a의 shape과 같아야 합니다.
a[b_indices] 형태로 boolean으로 인덱싱을 하면,
True가 위치한 인덱싱 번호를 가지고 a 에서 값을 가져오게 됩니다.
여기선 b_indices에서 true가 있는 인덱스번호는 0, 2, 4 입니다.
a에서 인덱스번호 0, 2, 4에 위치한 값은 무엇이죠?
네 바로 0 2, 4 입니다.
하지만 우리가 보통 실제로 리스트에 이런 boolean 형태 넣는 경우는 드뭅니다.
다만 넘파이가 내부적으로 이러한 연산을 한다는것을 챙겨 가시기 바랍니다.
실제로 어떻게 사용되는지는 아래에서 조건문 인덱싱을 통해 더욱 자세히 알아봅시다.
조건문을 통한 인덱싱
import numpy as np
a = np.random.randint(0, 20, (10,))
print(f"ndarray: \n{a}")
b_indices = (a % 2 ==0) # 짝수인부분만 True로 만들기
print(f"b_indices : \n{b_indices}")
print(f"a[b_indices]: \n{a[b_indices]}")
output :
이번에는 b_indices가 array의 형태가 아닌 조건문 형태 처럼 보입니다.
해당조건은 짝수인값을 찾는 조건입니다.
즉 짝수이면 true 값을 반환을 하는거이죠.
a 를 기준으로 짝수를 찾고 있기 때문에 a 원소들 각각을 확인하며 true 또는 false를 반환합니다.
output 의 b_indices 를 보시면 boolean 형태의 리스트를 보실 수 있습니다.
우리가 직접 true 또는 false를 넣지는 않았지만 내부적으로 해당 boolean 리스트를 만드는것을 직접 확인했습니다.
이후는 같은 방법으로 진행됩니다.
True인 값이 있는 인덱스를 찾고 그 인덱스에 해당하는 a값을 반환하는것이죠.
코드를 통해 차근 차근 살펴보시기 바랍니다.
2차원 행렬 boolean 인덱싱
import numpy as np
a = np.random.randint(0, 20, (2,2))
print(f"ndarray: \n{a}")
b_indices = np.array([[True, False],
[False, True]])
print(f"b_indices : \n{b_indices}")
print(f"a[b_indices]: \n{a[b_indices]}")
# True인 값만 뽑아서 차례대로 만들어줌.
# 결과를 벡터로 만들어줌..
output :
차원이 바뀌어도 기본 원리는 같습니다.
여기선 a가 2차원 행렬의 형태이네요.
b_indices도 a 의 shape과 맞춰 2,2 행렬을 만들었는데 boolean 값으로 구성을 하였습니다.
결과를 보시면 아시겠지만 True 인 값이 있는 위치, 즉 여기선 0,0, 1,1 인덱스를 이용하여 a값에서 값을 불러오는 것입니다.
a에서 0,0 의 값은 2, 그리고 1,1의 값은 6인걸 알수 있습니다.
여기서 참고할만한 사항은 기존 shape을 살리는게 아니라 벡터의 형태로 반환되는 것을 확인할 수있습니다.
실제로 사용되는 조건문을 적용할때는 어떨까요?
import numpy as np
a = np.random.randint(0, 20, (2,2))
print(f"ndarray: \n{a}")
b_indices = (a > 10) # 10보다 큰 값만 True로 만들겠다
print(f"b_indices : \n{b_indices}")
print(f"a[b_indices]: \n{a[b_indices]}")
output :
10보다 큰값을 true로 하겠다라는 조건입니다.
output에서 b_indices 를 보시면 True가 있는 index는 0,1 입니다. a에서 이 인덱스에 해당하는 값은 12 즉 최종결과를 확인 할 수 있습니다.
np.nonzero | np.where
import numpy as np
a = np.array([True, False, True, False])
nonzero = np.nonzero(a)
where = np.where(a)
print(f"a: \n{a}")
print(f"nonzero: \n{nonzero}") # True 인값만 뽑아냄
print(f"where: \n{where}") # True 인값만 뽑아냄
output :
boolean 인덱싱에서 조건문 이외에도 np.nonzero와 np.where가 있습니다.
내부적으로 어떻게 동작하는지 알기 위해 이번에도 boolean 데이터를 넣은 array를 이용해 작동원리를 배워봅시다.
이번엔 b_indices를 따로 지정하지 않고 a 가 boolean array형태입니다.
그리고 이 array를 nonzero , where api 의 인자로 집어넣습니다.
이 두 api가 어떤작동을 하는지는 결과를 보면 유추가능합니다.
둘다 a 에서 true가 있는 인덱스의 값을 반환합니다.
(a에서 True가 있는 인덱스는 0, 2)
둘이 똑같은 기능을 하는 것 같이 보입니다.
(둘의 차이는 해당 포스트에서 설명합니다. )
조건문과는 다르게 np.nonzero와 np.where는 True인 값의 인덱스를 반환하는점을 알아두시길 바랍니다.
2차원의 형태도 볼까요?
import numpy as np
a = np.array([[True, False],
[True, False]])
nonzero = np.nonzero(a)
where = np.where(a)
print(f"a: \n{a}")
print(f"nonzero: \n{nonzero}") # True 인값만 뽑아냄
print(f"where: \n{where}") # True 인값만 뽑아냄
output :
같은 원리로 a의 True 인 값의 인덱스를 찾는데요, 여기선 True는 (0,0), (1,0) 입니다.
이를 array로 표현하기 위해 [0,1] [0,0] 형태로 반환을 한것을 볼수가 있습니다.
즉 빨간색 끼리 (0,0), 파란색 끼리 (1,0) 이 두 인덱스의 값이 True라는걸 말해줍니다.
이어서 3차원으로 확장해보겠습니다.
import numpy as np
a = np.array([[[True, False],
[True, False]],
[[True, False],
[True, False]]])
nonzero = np.nonzero(a)
where = np.where(a)
print(f"a: \n{a}")
print(f"nonzero: \n{nonzero}") # True 인값만 뽑아냄
print(f"where: \n{where}") # True 인값만 뽑아냄
output :
a의 shape은 (2,2,2)의 3차원 텐서입니다.
앞서 배웠던것처럼 True인 값의 인덱스를 반환을 하는데요.
a에서 True 인 값의 인덱스는 (0,0,0), (0,1,0), (1,0,0), (1,1,0) 총 4개 입니다.
그리고 이를 array형태로 반환을 하게 됩니다.
이어서,
그렇다면 np.nonzero와 np.where가 반환하는 인덱스를 가지고 어떻게 활용할 수있는지 확인해보겠습니다.
인덱스를 이용한다는것은 "array[ 인덱스]"의 형태를 만든다는것이겠죠?
코드를 통해 확인해보겠습니다.
응용
import numpy as np
a = np.random.randint(-2, 3, size=(3,3))
print(f"a: \n{a}\n")
using_nonzero = a[np.nonzero(a)]
using_where = a[np.where(a)]
using_bool = a[a !=0]
print(f"using nonzero: \n{using_nonzero}")
print(f"using where: \n{using_where}")
print(f"using bool: \n{using_bool}")
output :
이번코드에서는 nonzero, where, 조건절 세가지 를 이용하여 코드를 작성 해보았습니다.
[참고로 boolean 작동원리상 0은 False이고 나머지는 다 True입니다. ]
nonzero 와 where은 앞서 배웠던것처럼 True 인 값의 인덱스를 가지고 값을 찾습니다.
여기선 0을 제외한 모든 값의 인덱스번호를 가져올것이고 이번호를 가지고 값을 불러 왔겠네요.
조건문의 경우는 명시적으로 a != 0 인것을 넣어줬습니다.
결가를 보시면 0을 제외한 모든값들이 예상대로 나온것을 확인할 수 있습니다.
이번에도 원래 shape은 사라지고 배열 형태로 반환이 되었습니다.
그런데 우리는 0이 아닌 값들이 아닌 0 이상의 값들을 뽑고 싶을뗀 어떻게 해아할까요?
조건문이야 a > 0하면 간단이 해결 될것이고.
nonzero와 where은요??..
감사하게도 nonzero와 where도 조건문을 넣을 수 있습니다.
import numpy as np
a = np.random.randint(-2, 3, size=(3,3))
print(f"a: \n{a}\n")
using_nonzero = a[np.nonzero(a>0)]
using_where = a[np.where(a>0)]
using_bool = a[a >0]
print(f"using nonzero: \n{using_nonzero}")
print(f"using where: \n{using_where}")
print(f"using bool: \n{using_bool}")
output :
위와 같이 a를 그냥 넣는게 아니라 a >0과 같이 새로운 조건을 넣어줌으로써 새로운 True, False조건을 만듭니다.
이글과 읽으면 좋은글
'머신러닝,딥러닝 > 넘파이,numpy' 카테고리의 다른 글
[넘파이 기초] np.repeat , np.tile (배열 반복 | array 복사) (0) | 2021.05.25 |
---|---|
[넘파이 기초] vstack | hstack | concatenate | dstack | stack 마스터 (4) | 2021.05.13 |
[넘파이 기초] 반올림, 올림, 버림 (0) | 2021.04.27 |
[넘파이 기초] axis, keepdims 마스터하기 (0) | 2021.04.23 |
[넘파이 기초] int ndarray로 인덱싱 (indexing) 하기 (0) | 2021.04.22 |
댓글