[Python Data Analysis]9.array 인덱싱 이해하기


array 인덱싱 이해하기

기본 인덱싱

numpy array의 꽃은 인덱싱(indexing)입니다. 기본적인 인덱싱은 Python 리스트와 매우 유사합니다. arr이라는 array가 있을 때, arr[5]와 같이 특정한 인덱스를 명시할 수도 있고, arr[5:8]과 같이 범위 형태의 인덱스를 명시할 수도 있습니다. arr[:]의 경우, 해당 array의 전체 성분을 모두 선택한 결과에 해당합니다.

이러한 인덱싱 방식은 2차원 array에 대해서도 아주 유사한 방식으로 적용됩니다. arr2d라는 2차원 array를 정의한 뒤, arr2d[2, :]를 실행하게 되면 arr2d에서 인덱스가 2에 해당하는 행(3행)의 모든 성분이 1차원 array의 형태로 얻어집니다. arr2d[:, 3]을 실행하면, arr2d에서 인덱스가 3에 해당하는 열(4열)의 모든 성분이 1차원 array의 형태로 얻어집니다.

2차원 array에서는 이렇게 두 개의 인덱스를 받을 수 있는데, ,를 기준으로 앞부분에는 ‘행’에 대한 인덱스가, 뒷부분에는 ‘열’에 대한 인덱스가 입력됩니다. arr2d[1:3, :]혹은 arr2d[:, :2]와 같이, 행 또는 열에 범위 인덱스를 적용하여 여러 개의 행 혹은 열을 얻을 수도 있습니다.

한편 2차원 array에서 4행 3열에 위치한 하나의 성분을 얻고자 하는 경우, arr2d[3, 2]를 실행하면 됩니다. 인덱싱을 통해 선택한 성분에 새로운 값을 대입하는 경우에도, arr2d[:2, 1:3] = 0과 같이 하면 됩니다.

여러 가지 방법으로 인덱싱을 시도하면서, array에 대한 인덱싱 방식에 익숙해지시길 바랍니다.

불리언 인덱싱

array와 관련하여 중요하게 사용되는 또 다른 인덱싱 방식이 불리언 인덱싱입니다.

    names = np.array(["Charles", "Kilho", "Hayoung", "Charles", "Hayoung", "Kilho", "Kilho"])
    data = np.array([[ 0.57587275, -2.84040808,  0.70568712, -0.1836896 ],
                     [-0.59389702, -1.35370379,  2.28127544,  0.03784684],
                     [-0.28854954,  0.8904534 ,  0.18153112,  0.95281901],
                     [ 0.75912188, -1.88118767, -2.37445741, -0.5908499 ],
                     [ 1.7403012 ,  1.33138843,  1.20897442, -0.58004389],
                     [ 1.11585923,  1.02466538, -0.74409379, -1.55236176],
                     [-0.45921447,  2.53114818,  0.5029578 , -0.24088216]])

위와 같은 names array와 data array가 정의되었다고 가정합시다. names array 내 각각의 성분이, data array의 각 행에 순서대로 대응된다고 가정합시다. 이러한 상황에서 이름이 “Charles”인 사람의 행 데이터만을 추출하고 싶다고 할 때, names == "Charles"를 실행하면 다음과 같은 결과를 얻을 수 있습니다.

    names == "Charles"
    >>>    array([ True, False, False,  True, False, False, False], dtype=bool)

얻어진 array를 잘 보면, 값이 “Charles”인 성분의 위치에는 True가, 그 외의 위치에는 False가 들어가 있는 것을 확인할 수 있습니다. 이렇게 names == "Charles"와 같은 조건식 형태의 코드를 실행하였을 때 생성되는 불리언 array를 다른 말로 ‘마스크(mask)’라고 합니다.

이런 마스크는 다른 array를 인덱싱하는 데 사용할 수 있습니다. 예를 들어 data[names == "Charles", :]를 실행하면, 위에서 보인 마스크가 True에 해당하는 행만을 data array로부터 가져오게 되고, 이들만으로 구성된 array를 얻을 수 있습니다.

    data[names == "Charles", :]
    >>> array([[ 0.57587275, -2.84040808,  0.70568712, -0.1836896 ],
               [ 0.75912188, -1.88118767, -2.37445741, -0.5908499 ]])

이러한 조건을 여러 개 추가할 수도 있습니다. 예를 들어 값이 “Charles” 혹은 “Kilho”인 성분에 대응되는 행을 얻고 싶다면, 다음과 같이 하면 됩니다.

    data[(names == "Charles") | (names == "Kilho"), :]
    >>> array([[ 0.57587275, -2.84040808,  0.70568712, -0.1836896 ],
               [-0.59389702, -1.35370379,  2.28127544,  0.03784684],
               [ 0.75912188, -1.88118767, -2.37445741, -0.5908499 ],
               [ 1.11585923,  1.02466538, -0.74409379, -1.55236176],
               [-0.45921447,  2.53114818,  0.5029578 , -0.24088216]])

혹은 기존의 data array의 각 성분의 값을 기준으로 불리언 인덱싱을 수행할 수도 있습니다. 예를 들어 data[:, 3]을 실행하여 4열만의 값을 본다고 할 때, data[:, 3] < 0을 실행하여 4열 상에서 그 값이 0보다 작은 성분을 조사하면, 다음과 같은 마스크를 얻을 수 있습니다.

    data[:, 3] < 0
    >>> array([ True, False, False,  True,  True,  True,  True], dtype=bool)

data array의 4열의 값이 0보다 작은 행에 대해서는 행 내 모든 성분에 0을 대입하도록 해 봅시다. 다음과 같이 하면 됩니다.

    data[data[:, 3] < 0, :] = 0

불리언 인덱싱은 처음 접할 때 굉장히 헷갈릴 수 있기 때문에, 여러분들이 직접 다양한 array에 대하여 반복 연습해 보면서 제대로 익힐 필요가 있습니다.




© 2017. by freelife

Powered by freelife