5. Boolean or "mask" index arrays
y = np.arange(35).reshape(5, 7)
# y = [[0, 1, 2, 3, 4, 5, 6],
# [7, 8, 9, 10, 11, 12, 13],
# [14, 15, 16, 17, 18, 19, 20],
# [21, 22, 23, 24, 25, 26, 27],
# [28, 29, 30, 31, 32, 33, 34]]
b = y > 20
print(y[b]) #[21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]
boolean을 인덱스에 사용하는 것도 가능하다.
대신 정수로 인덱싱하는 것과 다르게 출력값은 1차원이 된다.
참고로 print(y[b])와 print(y[np.nonzeros(b)])는 같은 출력값을 가진다.
참고로 b를 출력해보면,
[[False False False False False False False]
[False False False False False False False]
[False False False False False False False]
[ True True True True True True True]
[ True True True True True True True]]
y와 같은 모양의 boolean 행렬이 되어있는 것을 알 수 있다.
때문에 boolean으로 인덱싱 하고도 y와 같은 차원을 갖는 출력값을 얻기 원한다면, b를 인덱싱한 것으로 y를 인덱싱 하면 된다(저번 글에 배열로 배열을 인덱싱 하는 것을 적어놓았음).
# b[: , 5] = [False False False True True]
print(y[b[ : , 5]])
# [[21 22 23 24 25 26 27],
# [28 29 30 31 32 33 34]]
b[:, 5]의 마지막 2개만 True이므로 2차원 행렬인 y의 4, 5번째 행 만을 출력한다.
처음부터 b를 boolean배열로 만들어서 인덱싱하는 것도 가능하다.
x = np.arange(30).reshape(2, 3, 5)
# [[[ 0 1 2 3 4]
# [ 5 6 7 8 9]
# [10 11 12 13 14]]
#
# [[15 16 17 18 19]
# [20 21 22 23 24]
# [25 26 27 28 29]]]
b = np.array([[True, True, False], [False, True, True]])
print(y[b])
# [[ 0 1 2 3 4]
# [ 5 6 7 8 9]
# [20 21 22 23 24]
# [25 26 27 28 29]]
하지만 출력은 한 차원 적게 나온다. 행렬로 뽑아냈으니 그런건가.
f = np.arange(15).reshape(3, 5)
b1 = np.array([True, True, False])
b2 = np.array([False, True, False, True, True])
print(f[b1, :])
# [[0 1 2 3 4]
# [5 6 7 8 9]]
print(f[:, b2])
# [[ 1 3 4]
# [ 6 8 9]
# [11 13 14]]
참고로 여기서 print(f[b1, b2])는 오류가 난다.
IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (3,)
6. Combining index arrays with slices
저번 글에 적었던 것 처럼 범위를 정해서 행렬을 잘라내는 것을 해보자.
print(y[np.array([0, 2, 4]), 1:3])
여기서도 마찬가지로 np.array([0, 2, 4])라는 배열을 이용해 y의 행의 범위를 정해준다.
[[0 1 2 3 4 5 6]
[14 15 16 17 18 19 20]
[28 29 30 31 32 33 34]]
여기서 1:3으로 인덱스 1에 해당하는 열부터 인덱스 3-1에 해당하는 열까지 슬라이스 한다.
[[1 2]
[15 16]
[29 30]]
퀵 튜토리얼에 다른 예도 많이 나오니 같이 적어놔야겠다.
p = np.arange(12).reshape(3, 4)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
u = np.array([[0, 1],
[1, 2]])
v = np.array([[2, 1],
[3, 3]])
# [[ 2 5]
# [ 7 11]]
u의 [0, 1]은 p의 인덱스 0, 1 번째에 해당하는 행을, 출력할 행렬의 인덱스 0의 범위로 지정한 것이고
[0 1 2 3]
[4 5 6 7]
[1, 2]는 p의 인덱스 1, 2번째에 해당하는 행을, 출력할 행렬의 인덱스 1의 범위로 지정한 것이다.
[4 5 6 7]
[8 9 10 11]
v의 [2, 1]은 u가 지정한 인덱스 0의 범위에서 각각 인덱스 2, 1에 해당하는 열의 요소를 가져오라는 것이고
[0 1 2 3]
[4 5 6 7]
[3, 3]는 인덱스 1의 범위에서 각각 인덱스 3, 3에 해당하는 열의 요소를 가져오라는 것이다.
[4 5 6 7]
[8 9 10 11]
더 간단히 하기 위해 s = np.array([u, v])라 하고 p[s]를 출력하면 IndexError가 일어나지만 p[tuple(s)]라 하면 위와 동일한 결과를 얻을 수 있다.
7. Structural indexing tools
축을 추가해 차원을 늘리는 방법으로는 np.newaxis가 있다.
아직까지 100% 이해된 것이 아니기 때문에 여러 변주를 주면서 적어보겠다.
print(x[np.newaxis])와 print(x[np.newaxis, :])는 같은 값이 출력되므로 하나만 적겠다.
z = np.arange(12).reshape(4, 3)
# [[0 1 2]
# [3 4 5]
# [6 7 8]
# [9 10 11]]
print(x[np.newaxis])
# [[[0 1 2]
# [3 4 5]
# [6 7 8]
# [9 10 11]]]
print(x[np.newaxis, np.newaixs])
# [[[[0 1 2]
# [3 4 5]
# [6 7 8]
# [9 10 11]]]]
print(x[:, np.newaxis, :])와 print(x[:, np.newaxis])는 같은 값이 출력되므로 하나만 적겠다.
print(x[:, np.newaxis, :])
# [[[0 1 2]]
#
# [[3 4 5]]
#
# [[6 7 8]]
#
# [[9 10 11]]]
print(x[:, np.newaxis]*2)
# [[[0 2 4]]
#
# [[6 8 10]]
#
# [[12 14 16]]
#
# [[18 20 22]]]
print(x[:, np.newaxis]*x)
# [[[ 0 1 4]
# [ 0 4 10]
# [ 0 7 16]
# [ 0 10 22]]
#
# [[ 0 4 10]
# [ 9 16 25]
# [ 18 28 40]
# [ 27 40 55]]
#
# [[ 0 7 16]
# [ 18 28 40]
# [ 36 49 64]
# [ 54 70 88]]
#
# [[ 0 10 22]
# [ 27 40 55]
# [ 54 70 88]
# [ 81 100 121]]]
위에 적은 x[:, np.newaxis]*2는 각 행의 차원을 하나 늘린 후 2를 곱한 값이다. 3차원 텐서가 출력됐다.
아래 적은 x[:, np.newaxis]*x는 전체 텐서에 각 행을 순서대로 곱한 것이다. 즉
x의 첫 번째 행 [0 1 2]를 x 에 element-wise로 곱한다. 그것이 [[0 1 4], [0 4 10], [0 7 16], [0, 10, 22]]가 된다.
x의 두 번째 행 [3 4 5]를 마찬가지로 곱한다. 그것이 [[0 4 10], [9 16 25], [18 28 40], [27 40 55]]가 된다.
이렇게 다 곱하면 x.shape = (4, 4, 3)인 3차원 텐서가 출력된다.
: 의 위치를 바꿔주면 출력값은 완전히 달라진다.
print(x[np.newaxis, :]*2)
# [[[ 0 2 4]
# [ 6 8 10]
# [12 14 16]
# [18 20 22]]]
print(x[np.newaxis, :]*x)
# [[[ 0 1 4]
# [ 9 16 25]
# [ 36 49 64]
# [ 81 100 121]]]
x[np.newaxis, :]*2의 경우 2차원 행렬에 2를 곱해 차원을 하나 늘린 3차원 텐서가 출력되고, x[np.newaxis, :]*x의 경우 2차원 행렬에 2차원 행렬 x를 element-wise로 곱한 뒤 차원이 하나 늘어난 3차원 텐서를 출력한다.
'파이썬3 노트' 카테고리의 다른 글
numpy 공부: [선형대수] (0) | 2018.08.10 |
---|---|
numpy 공부: [Indexing] (3) (0) | 2018.08.09 |
numpy 공부: [indexing] (1) (0) | 2018.08.07 |
모듈/함수 공부: [데이터 모델] ① (0) | 2018.06.15 |
모듈/함수 공부: [typing] [@property] [[int, ...]] (0) | 2018.06.13 |