NumPy에서 indexing은 4가지 방식을 따름.
- scalar를 이용한 indexing ( simple indexing ) :
array[0]
- slicing
- boolean mask :
array[array > 1]
- fancy indexing : vectorized indexing. index들을 element로 가지는 array를 넘겨줌.
- combined indexing : 앞서 4가지가 조합된 indexing
Fancy Indexing
image(or matrix)등에서 높이 (row, height), 넓이 (column, width)에 대해, 접근하고자하는 pixel (or entry)들의 index를 square bracket안에 넘겨주는 방식임.
간단하게 1차원에서 확인한다면 다음과 같음.
import numpy as np
x = np.array([0,1,2,3,4,5,6,7,8])
Fancy indexing은 다음과 같이 index로 구성된 array를 index위치에 넘겨줌.
fidx = [3, 7, 1]
x[fidx] # array([3, 7, 1])
Fancy indexing의 특징 중 하나는 넘겨준 fancy indexing의 shape에 맞추서 결과 ndarray가 만들어진다.
fidx =[[3, 7],
[4, 2]]
fidx = np.array(fidx)
x[fidx] # array([[3,7],[4,2]])
fidx
가 $2\times 2$ matrix이므로x[fidx]
도 $2\times 2$ matrix가 됨.
Fancy indexing에서 각 axis에 대한 index를 따로 지정하는 경우도 매우 많음.
x = x.reshape((3,3))
ridx = np.array([0,1,2])
cidx = np.array([2,0,1])
x[ridx,cidx] # array([2, 3, 7])
강력한 점은 broadcasting rule을 통해 해당 index들의 array들이 최종 index들의 ndarray가 된다는 점임.
x[ ridx[:,np.newaxis], cidx]
결과는 다음과 같음.
array([[2, 0, 1],
[5, 3, 4],
[8, 6, 7]])
ridx
가 $3 \times 1$ 이므로cidx
와 broadcasting이 이루어져 최종 idx는 다음과 같음.
$$\begin{bmatrix} \text{(0,2)} & \text{(0,0)} & \text{(0,1)} \\ \text{(1,2)} & \text{(1,0)} & \text{(1,1)} \\ \text{(2,2)} & \text{(2,0)} & \text{(2,1)} \end{bmatrix}$$
2022.09.27 - [Programming/DIP] - [NumPy] Broadcasting
Combined Indexing
fancy indexing은 나머지 indexing기법과도 조합하여 사용가능함.
x[2, [2, 0, 1]] # combination between simple indexing and fancy indexing
결과는 다음과 같음.
array([8, 6, 7])
x[::-1, [0,2]] # combination b/w slicing and fancy indexing
결과는 다음과 같음.
array([[6, 8],
[3, 5],
[0, 2]])
boolean mask와도 조합이 가능함.
mask = np.array([True, False, True])
x[mask,cidx[:,np.newaxis]]
위의 코드는 다음과 같은 코드임.
x[[0,2],cidx[:,np.newaxis]]
- 주의할 건, boolean mask의 경우, broadcasting을 할 때
True
인 부분들만이 실제로 shape에 카운팅이 됨. - 위의 코드에서 boolean mask가 3개의 요소로 보이나 broadcasting 규칙을 적용할 때는 실제로는 2개의 요소만을 가진 ndarray로 간주됨.
- 때문에 broadcasting에서 각 축의 요소수가 맞지 않아 문제가 발생 할 수 있음. 주의필요.
Fancy indexing을 이용하여 특정 item의 값을 변경할 수 있으나, 같은 index가 여러번 나온다고 해도 변경연산이 누적(혹은 반복)되진 않음.
x = np.arange(10)
i = np.array([9, 1, 3, 9])
x[i] = x[i] +10
x
결과는 다음과 같음.
array([ 0, 11, 2, 13, 4, 5, 6, 7, 8, 19])
- 주의할 부분은 9를 index로 가지는 부분으로 fancy indexing에서 2번 지정되었다고 10이 더해지는 연산이 2번 누적해서 일어나지 않음.
이같이 반복 처리를 하려면 at
메소드를 활용해야함.
x = np.arange(10)
np.add.at(x,i,10)
x
결과는 다음과 같음.
`array([ 0, 11, 2, 13, 4, 5, 6, 7, 8, 29])`
https://gist.github.com/dsaint31x/eb7a1fcc729ba3f349d7259002318976#file-fancyindexing-ipynb
'Programming > DIP' 카테고리의 다른 글
[DIP] Image Format (summary) (0) | 2022.12.05 |
---|---|
[DIP] Deconvolution : Richardson-Lucy deconvolutoin algorithm (0) | 2022.10.11 |
[DIP] opencv : Region of Interest (ROI) : (0) | 2022.10.03 |
[DIP] opencv : Region of Interest (ROI) : cv2.selectROI (0) | 2022.10.03 |
[NumPy] Broadcasting (0) | 2022.09.27 |