STUDY LOG/Kaggle

Pandas(2)

Jinwang Mok 2021. 9. 26. 18:39

인덱싱, 선택 그리고 할당

전문 데이터 사이언티스트는 이 일에 하루의 절반을 쏟는다. 당신도 마찬가지!

 

소개

작업을 하기위해 Pandas의 데이터프레임이나 시리즈에서 특정 값을 선택하는 것은 거의 모든 데이터 활용에서 필수적인 단계이다. 따라서, 당신이 파이썬으로 데이터 작업을 하는 것에 있어서 먼저 배워두어야 하는 것 중 하나는 어떻게 당신과 관련된 데이터를 빠르고 효율적으로 선택하느냐 하는 것이다.

 

import pandas as pd
reviews = pd.read_csv('../input/wine-reviews/winemag-data-130k-v2.csv', index_col=0)
pd.set_option('max_rows', 5)

고유 접근자(Native accessors)

기존 파이썬 오브젝트는 데이터를 인덱싱하는데 좋은 방법을 제공한다. Pandas는 이 시작하기 쉽게 만드는 모든 것들을 포함한다.

reviews

 

파이썬에서는 속성으로 오브젝트의 property에 접근할 수 있다. 예를 들어, book이라는 오브젝트가 있다고 가정하자. 이 오브젝트가 title이라는 property를 가졌다고 하고, 우리가 이것에 접근하기 위해서는 book.title이라고 하면 된다. Pandas의 데이터프레임 또한 마찬가지다. 데이터프레임에서 열, 그러니까 속성에 접근하려면 다음과 같다. 아래는 country라는 property(=속성)에 접근하는 코드이다.

reviews.country

 

또한, 파이썬의 딕셔너리에서 특정 키의 값에 접근하려면 [] 를 사용해 인덱싱을 한다. 이 또한 데이터프레임에서 마찬가지로 적용된다.

reviews['country']

 

이 두가지 방법은 데이터프레임에서 특정 시리즈를 선택하는 방법이다. 두가지 방법 모두 문법적으로 뭐가 더 낫다고 할 수 없지만, [] 를 사용하는 것의 장점이 하나 있다. 바로 예약된 문자(공백 같은)가 포함된 이름에도 접근할 수 있다는 것이다. 즉, 만약 country providence라는 다른 열이 있다고 하면, reviews.country providence는 작동하지 않는데, 이 경우 []는 가능하다는 것이다.

 

Pandas의 시리즈가 좀 세련된 딕셔너리 같지 않은가? 실제로 거의 그렇다고 할 수 있다. 따라서, 더 나아가 단 하나의 특정 항목(엑셀의 셀 한 개의 개념)에 접근할 수 있다는 것이 놀랍지 않을 것이다. 그냥 [] 하나 더 붙이면 된다.

reviews['country'][0]

 

Pandas에서의 인덱싱

인덱싱 연산자([])와 속성 선택 연산자(.)는 원래 파이썬과 똑같이 동작하기 때문에 좋다. 초심자라면 이를 통해 쉽게 선택하고 사용할 수 있을 것이다. 하지만, Pandas는 Pandas만의 접근 연산자가 존재한다. 바로 lociloc이다. 더 전문적인 작업을 위해서는 이걸 사용할 필요가 있다.

 

인덱스 기반 선택

Pandas 인덱싱은 두 가지 체계 중 하나로 작용한다. 첫번째는 인덱스 기반 선택(index-based selection), 데이터 내의 숫자형 위치에 기반하여 선택하는 것이다. iloc가 이 체계를 따른다.

데이터프레임의 첫번째 행 데이터를 선택하는 것은 아래와 같다.

reviews.iloc[0]

 

loc와 iloc 모두 행이 우선, 열이 차선이다. 이것을 언급하는 이유는 기존 파이썬에서는 반대로 동작하기 때문이다.

 

또, 이 말은 행을 가져오는 것이 아주 조금 더 쉬워졌고, 열을 가져오는 것은 아주 조금 더 어려워졌다는 것이다. 순서가 바뀌었기 때문에! 만약, iloc로 행을 가지고 오고 싶다면, 아래와 같다.

reviews.iloc[:, 0] #행 전체, 열은 0번 인덱스 선택

: 는 기존 파이썬에서처럼 전체를 의미한다. 하지만, 다른 선택자와 결합하면 값의 범위를 나타내는 것에 사용할 수 있다.

 

예를 들어, country 열의 첫번째, 두번째, 세번째 행을 가져오려면 아래와 같이 명령하면 된다.

reviews.iloc[:3, 0]

또, 두번째와 세번째 항목만 가져오려면, 아래와 같다.

reviews.iloc[1:3, 0]

또, 리스트로 대체하는 것도 가능하다.

reviews.iloc[[0, 1, 2], 0]

마지막으로, 음수도 선택에 사용 가능하다. 음수는 파이썬에서와 마찬가지로 반대 방향을 의미한다. 따라서, 데이터셋의 마지막 5개를 가져오는 명령은 다음과 같다.

reviews.iloc[-5:]

 

레이블 기반 선택

두번째 체계는 loc를 사용해서 속성을 선택할 수 있는 레이블 기반 선택(label-based selection)이다. 이 체계에서 데이터 인덱스 값은 위치가 아니라 성분matters이다.

예시를 통해 빠르게 이해해보겠다. reviews에서 첫번째 요소에 접근하기 위해서는 아래와 같이 명령할 수 있다.

reviews.loc[0, 'country']

 

iloc가 loc보다 개념적으로 더 단순하다. 왜냐하면, iloc는 데이터셋의 인덱스를 몰라도 사용가능하기 때문이다. iloc를 사용할 떄, 우리는 데이터셋을 그냥 큰 행렬로 다루기 때문에, 인덱스에서는 숫자 위치를 던져주면 된다. 하지만 이와 반대로 loc는 인덱스의 정보를 사용하여 작업을 수행한다. 당신의 데이터셋이 대체로 유의미한 인덱스 정보를 가지고 있기 때문에, 대체로 loc를 쓰는게 더 쉬울 수 있다.

예를 들어 아래에는 loc를 사용해 더 쉽게 선택하는 예제이다.

reviews.loc[:, ['taster_name', 'taster_twitter_handle', 'points']]

 

 

loc와 iloc 중에서 선택하기

loc와 iloc 중에서 선택할 때, 두 메소드가 살짝 다른 인덱스 구조를 가지고 있다는 것을 꼭 기억하길 바란다.

 

iloc는 파이썬의 stdlib 인덱싱 구조를 사용한다. 이는 선택 범위의 첫번째 요소는 포함하고 마지막 요소는 제외한다는 것이다. 예를 들어 0:10이면, 0부터 9까지를 선택하는 것이다.

반면, loc는 이를 포함하여 인덱싱한다. 즉, 0:10이라면 0부터 10까지라는 것이다!

 

왜 이렇게 다른 것일까? loc는 문자열 등과 같은 어떤 stdlib 타입도 인덱스가 될 수 있다는 것을 기억해야 한다. 만약 우리의 데이터프레임이 Applls, ..., Potatoes, ... 와 같은 문자열 인덱스를 가지고 있다고 하고, 이중에서 Apples와 Potatoes 사이의 알파벳에 해당하는 과일을 선택하고자 한다면, df.loc['Apples' : 'Potatoes']라고 쓰는게 df.loc['Apples' : 'Potatoez']이라고 쓰는 것보다 편하기 때문이다.

 

이거는 숫자형 리스트(0, ..., 1000)인 인덱스로 이루어진 데이터프레임을 다룰 때 특히 햇갈리는 점이다. 이 경우 df.iloc[0:1000]이 1000개의 항목을 리턴하고 df.loc[0:1000]은 1001개의 항목을 리턴할 것이다..! 이 때 loc로 1000개의 항목을 가져오려면 df.loc[0:999]를 사용해야 할 것이다.

 

이 외에는 loc와 iloc는 동일한다.

 

인덱스 다루기

레이블 기반 선택은 인덱스의 레이블에서 힘을 얻고, 결정적으로 우리가 사용하는 인덱스는 변하지 않는다. 우리는 우리가 적절하다고 생각하는 어떤 방법이로든 인덱스를 다룰 수 있다.

 

set_index() 메소드는 이 일을 할 수 있게 해준다. 아래에는 우리가 title 필드에 set_index를 적용할 때 어떻게 되는가하는 예시다.

reviews.set_index('title')

이렇게 하면, title이라는 필드가 index로 적용된다.

이는 현재 데이터셋보다 나은 데이터셋에 대한 인덱스를 작성할 수 있는 경우에 유용하다.

 

조건 선택

지금까지 우리는 데이터프레임의 구조적인 특징을 이용해서 인덱싱해왔다. 하지만, 이 데이터로 흥미로운 것들을 하기 위해서는 종종 조건에 따라 질의해야 한다.

 

예를 들어, 우리가 이탈리아에서 생산되는 평균보다 더 좋은 와인에 특별히 관심이 있다고 가정해보자.

 

일단, 각 와인이 이탈리아산인지 아닌지 확인하는 것부터 시작할 수 있겠다.

reviews.country == 'Italy'

 

이 동작은 각 레코드의 country에 따라 True/False 값을 담고있는 시리즈를 제공한다. 이 결과값은 관련 데이터를 얻기위해 loc에 사용될 수 있다.

reviews.loc[reviews.country == 'Italy']

이렇게 되면, loc[0:3]이 loc[[0, 1, 2, 3]]과 같은 것처럼 불리언 타입으로 선택할 True인 행의 정보를 리스트, 정확히는 시리즈 형태로 넘겨주게 되는 것이다.

 

이 경우 원 데이터셋은 약 130,000개의 레코드로 이루어져있는데, 이탈리아산인 레코드는 약 20,000개인 것을 확인할 수 있다. 즉, 15%와인은 원산지가 이탈리아라는 것이다.

 

우리는 또한 어떤 것이 평균보다 더 좋은 것인지 알고 싶다. 와인은 80에서 100점 사이로 평가된다. 이 말은 적어도 90점 이상을 기록한 와인은 평균보다 좋은 와인이라는 것이 된다.

 

우리는 &(ampersand) 기호로 두 조건을 묶을 수 있다.

reviews.loc[(reviews.country == 'Italy') & (reviews.points >= 90)]

이 경우 6,648개의 레코드가 해당된다.

 

 

만약, 우리가 이탈리아산이거나 또는 평균보다 좋은 와인을 선택하고자 한다면, & 대신 |(pipe)를 사용할 수 있다.

reviews.loc[(reviews.country == 'Italy') | (reviews.points >= 90)]

이 경우 61,937개의 레코드가 해당된다.

 

 

또한, Pandas는 몇개의 내부 조건 선택자를 가지고 있는데 여기서는 그 중 두가지를 살펴보고자 한다.

 

첫번째는 isin이다. isin은 데이터의 전체 값들 중 해당 값이 포함된 값을 선택한다.

예를 들어, 이탈리아산과 프랑스산 와인을 선택하려면 다음과 같다.

reviews.loc[reviews.country.isin(['Italy', 'France'])]

이 경우 41,633개의 레코드가 해당된다.

 

두번째는 isnull과 그 짝인 notnull이다. 이 메소드들은 NaN이거나 NaN이 아닌 값들을 찾아낸다.

예를 들어, 데이터셋의 가격이 비어있는 레코드를 걸러내려면 다음과 같이 명령할 수 있다.

reviews.loc[reviews.price.notnull()]

이 경우 120,975개의 레코드가 해당된다. 약 1만개의 레코드는 가격이 없다고도 볼 수 있다.

 

데이터 할당

반대로 데이터프레임에 데이터를 할당하는 것은 쉽다. 상수 값을 할당 할 수 있다.

reviews['critic'] = 'everyone'
reviews['critic']

 

또는 연속적인 값도 가능하다.

reviews['index_backwards'] = range(len(reviews), 0, -1)
reviews['index_backwards']

이렇게 Pandas의 두번째 강의를 번역하며 공부해봤습니다.

 

오늘 배운 내용을 요약하자면,

  • 데이터프레임을 인덱싱하는 방법으로 기존 파이썬에서 객체의 속성에 접근하는 것처럼 (df.key)을 사용하거나, 딕셔너리에서 접근하는 것처럼 ['key']를 사용할 수 도 있지만(이 경우 뒤에 []하나 더 붙여서 개별 항목 접근도 가능), Pandas에서 제공하는 loc와 iloc를 사용할 수 도 있다.
    • iloc와 loc 모두 [] 내부에 행을 우선, 열을 차선하여 입력하므로써 선택할 수 있지만, iloc는 인덱스 기반 선택으로 숫자로 선택하며, loc는 레이블 기반 선택으로 숫자 이외에도 문자열 등으로도 선택할 수 있었다. 또한, 내부적으로 살짝 달라서 iloc는 0:10라고 하면, 0부터 9까지이지만 loc는 0부터 10까지이다. 이는 문자열을 다루는 loc에 맞는 특성이라고 볼 수 있다.
    • df.set_index('column-name')으로 해당 열의 값을 인덱스로 설정할 수 있었다.
  • 데이터프레임에서 조건으로 데이터를 선택할 수 있었는데, 좌항에는 df.column 이런식으로 조건을 검사할 열이 오고, 연산자로 비교 연산자 ==, >, <, >=, <= 등이 오고, 우항에 비교할 값이 온다. 이를 통해 얻을 수 있는 것은 해당 열의 조건 검사된 불리언 리스트이고, 이를 loc를 사용해 데이터프레임에서 인덱싱하여 원하는 조건의 데이터를 추려낼 수 있다.
    • ex1) my_df.loc[(df.Price >= 100) | (df.Size >= 30)]
    • 위의 예시와 같이 &나 |를 사용하여 and, or 연산도 할 수 있다.
    • Pandas에서 제공하는 내장 조건 연산도 있는데, isin과 isnull, notnull이 그것이다. 각각 isin은 isin의 인자로 넘긴 값이 있으면 True, 없으면 False를 리턴하고, isnull은 해당 레코드가 NaN 즉, 값이 없다면 True 있다면 False를 리턴하며 notnull은 그와 반대로 동작한다.
      • ex2) my_df.loc[(my_df.Price.isin([110, 120, 130]) & my_df.Size.notnull()]
  • 데이터프레임에 데이터를 할당하는 것은 매우 간단하다. 위의 기법으로 열이나 개별 요소를 선택하고 할당연산자(=)를 통해 값을 할당하면 된다. 열인 경우 해당 열의 값이 모두 해당 값으로 치환된다.

혹시라도 잘못된 내용이 있다면, 말씀해주시면 감사하겠습니다.

 

출처 : https://www.kaggle.com/residentmario/indexing-selecting-assigning