[Python.NumPy] ndarray indexing과 slicing

2020. 11. 30. 20:57Python과 머신러닝/NumPy 데이터 분석

0. 요약

  • ndarray를 쓰면 기존 Java나 C와는 다르게 배열을 참조하는데 세미콜론(:)이 꼭 들어간다.
  • 기존 프로그램을 짜 봤던 사람이라면 indexing은 쉽겠지만, slicing을 이해하는건 꽤나 까다롭고 처음엔 약간 변태적(?)인 문법이라는 생각이 들기도 한다.
  • 이걸 한번에 이해할 수 있는 원리와 예제들을 한번 정리하고자 한다.
import numpy as np

test_list = [[1, 2, 5, 8], 
             [2, 3, 6, 9], 
             [3, 4, 7, 10],
             [4, 5, 8, 11]] # 4 x 4 array
test_array = np.array(test_list, int)

print(test_array[1][2]) # 6 출력
print(test_array[1, 2]) # 동일하게 6 출력

test_array[1:2, :2] # 1번행 이상 / 2번행 미만, 2번 열 미만 출력
test_array[1, :2] # 동일하게 출력되지만, 위에는 2차원, 이 코드는 1차원으로 출력

test_array[:, 2:] # 모든 행, 2번 열 이후 출력

test_array[:, ::2] # 모든 행 + 모든 열을 2칸씩 띄워서

test_array[1::2, 0:4:3] # 1번 행부터 끝까지, 2행씩 띄워서 출력
                        # 0번 열부터 4번 미만 열까지, 3열씩 띄워서 출력

 

1. Indexing

import numpy as np

test_list = [[1, 2, 5, 8], 
             [2, 3, 6, 9], 
             [3, 4, 7, 10],
             [4, 5, 8, 11]] # 4 x 4 array
test_array = np.array(test_list, int)

print(test_array[1][2]) # 6 출력
print(test_array[1, 2]) # 동일하게 6 출력
  • 위와 같이 4x4 배열을 ndarray 형태로 변환하였다고 하면, indexing은 대부분의 코드가 동작하는 것과 비슷하다.
  • 각 차원 별로 대괄호 []를 써서 접근할 수 있다.
  • 예제처럼 [1][2]로 접근하여 6이라는 값에 접근할 수 있다. (0-base indexing이기 때문에 첫 줄은 0번 줄이다)
  • ndarray에서 다른 점이 있다면 [1, 2]로 접근을 해도 동일하게 접근이 가능한 점이다.
  • 나는 C 기반의 코딩을 처음 시작했기 때문에 이 접근이 매우 낯설지만, 최소한 다른 프로그램을 볼 땐 동일하다는 걸 이해하기 위해 한 줄 추가로 정리했다. 

 

2. Slicing 예제 #1

test_array[1:2, :2] # 1번행 이상 / 2번행 미만, 2번 열 미만 출력
  • Indexing은 기타 코드/프로그램과 유사하다면, slicing은 난생처음 본 문법/기능이었다.
  • Slicing이란 배열 중에서 원하는 부분만 뽑아 쓰기 위해 '잘라서 사용하는' 기능이다.
    (그래서 이름이 slicing인 것 같다)
  • 위의 예제를 보면, 행의 위치에 1:2라는 것은 1이상 & 2 미만을 뜻한다.
  • 행 위치에 있으니 1 이상 2 미만의 행을 의미하는 것이고, 같은 값이 콤마 뒤에 있었다면 1 이상 2 미만의 열이 되었을 것이다.
  • 예제의 열 위치에 있는 :22미만을 뜻한다. 즉, 2 미만의 모든 열을 slice 하라는 의미이다.
  • test_array[1:2, :2][[2,3]]의 값을 반환하게 된다.

 

3. Slicing 예제 #2

test_array[1, :2] # 동일하게 출력되지만, 위에는 2차원, 이 코드는 1차원으로 출력
  • 행은 1번 행을 읽어온다.
  • 열은 2 미만의 열을 읽어온다.
  • 그렇기 때문에 데이터는 [2, 3]이 반환되어 1번 예제와 동일한 결과물 같아 보이지만,
  • 2번 예제는 1차원 배열을 반환하고, 1번 예제는 2차원 배열을 반환하기 때문에 필요에 따라 골라서 사용해야 한다.

 

4. Slicing 예제 #3

test_array[:, 2:] # 모든 행, 2번 열 이후 출력
  • 행에 세미콜론(:)만 있는 것'모든 행'을 뜻한다.
  • 열의 2:2 이상의 모든 열을 뜻한다.
  • 합치면 모든 행의 2열 이상의 데이터를 가져오라 는 의미가 된다.
  • 결과물은 다음의 배열이 될 것이다
    [[58],
     [69],              
     [710],
     [811]] # 4 x 2 array

 

5. Slicing 예제 #4

test_array[1::2, 0:4:3] # 1번 행부터 끝까지, 2행씩 띄워서 출력
                        # 0번 열부터 4번 미만 열까지, 3열씩 띄워서 출력
  • 이건 예제로 정리해도 여전히 헷갈리는 개념이다.
  • Start:End:Interval의 문법을 사용한다.
  • 그리고 아무런 값이 없을 경우의 Default 값은 Start = 0, End = Total Row/Col count, Interval = 1이다.
  • 행의 1::2는 1번부터 시작해서, 끝까지 출력하되, 2 행씩 건너뛰어서 출력하라는 것이다. (1번, 3번 행 출력)
  • 열의 0:4:30번 열부터 시작해서, 4번 열 미만까지 출력하되, 3열씩 건너뛰어서 출력하라는 것이다. (0번, 3번 열 출력)
  • 결과적으로는 다음 2x2 배열이 나온다.
    [[2,4],
     [9,11]]

 

6. Slicing 예제 #5

test_array[:, ::2] # 모든 행 + 모든 열을 2칸씩 띄워서
  • 이번 포스트의 마지막 예제이다.
  • 모든 행의 데이터를 출력하라.
  • 모든 열을 출력하되, 짝수번째 열들만 출력하라.
  • 결과물은 다음 4x2배열이 될 것이다.
    [[1, 5],
     [2, 6],           
     [3, 7],
     [4, 8]] # 4 x 2 array

 

7. 마무리

  • Indexing은 비교적 단순하다. 각 dimension 별로 값을 주면, 해당 위치의 값을 반환해주는 것이 전부다.
  • Slicing은 생각보다 간단하지 않지만, 원리만 이해하고 나면 쉽게 적용이 된다.
    1. Start:End:Interval의 문법으로 Slice 할 위치를 지정한다.
    2. 각 위치의 default 값은 0:Total count:1이다.
  • 그래서 Start index를 생략하면 처음부터 전부라는 의미이고
  • End Index를 생략하면 끝까지 전부라는 의미이고
  • Interval을 생략하면 건너뛰지 않고 전부라는 의미이다.
  • 처음 강의를 들을 때만 해도 참 어려웠지만, 정리하고 보니 참 잘 만들고 요긴하게 사용될 기능 같다.
  • C에서 이런 걸 하려면 반복문을 몇개 써야 될지 생각만 해도 머리가 아파오는데, 그에 비해 위에 원리만 이해하면 NumPy의 ndarray는 아주 쉽게 사용하도록 만들었다.

 

관련 글

2020/11/30 - [Python과 머신러닝/Python 데이터 수집] - NumPy의 ndarray 이해하기

2020/11/30 - [Python과 머신러닝/Python 데이터 수집] - ndarray.reshape - 크기 변환하기

 

반응형