본문 바로가기

개발/파이썬

자주쓰는 명령어로 배우는 Pandas #4 : 데이터 능숙하게 다루기

반응형

자주쓰는 명령어로 배우는 Pandas 3편에 이어 4편입니다. 이번 편이 마지막 편입니다! 1편, 2편, 3편에서 작성했던 코드 결과들은 계속 유지되니 직접 실습을 따라 하고 싶으신 분들은 이전 시리즈를 참고해주세요.

지난번 실습까지 잘 따라오셨다면, 아래와 같은 데이터 프레임을 가지고 있으실 겁니다.

df.head()

실행결과

참고사항: 이번 포스트에서 보여드리는 대부분의 예시에서는 원본 df를 변경시키지 않기 위해 연산 결과를 다시 df에 지정시키지 않습니다. 연산 결과로 데이터를 변경시키기 위해서는 df = 연산결과구문을 활용해서 원본 데이터를 변경해주시면 됩니다.

데이터 마스킹(Masking) 하기

요즘 코로나 때문에 모두들 마스크를 써서 입을 가리죠? 데이터에서도 일부 데이터를 가린다는 의미로 '마스킹'이라는 용어를 씁니다. 주가 데이터에서 관리종목 데이터를 가리는 등의 용도로 사용할 수 있습니다.

Mask

mask 메소드를 이용하면 조건을 만족하는 데이터를 특정한 값으로 마스킹할 수 있습니다.

df.mask(<조건>, <마스킹할 값>)

이번 예제에서는 Salary가 6000 미만인 데이터를 NaN으로 마스킹해보겠습니다.

import numpy as np  # numpy 임포트

df.mask(df["Salary"] < 6000, np.nan)

실행결과

Salary가 6000 미만인 데이터의 행이 모두 NaN값으로 바뀐 것을 확인하실 수 있습니다.

Where

where메소드는 mask와 정확히 반대의 역할을 합니다. where메소드는 조건을 만족하지 못하는 데이터를 마스킹합니다.

df.where(<조건>, <마스킹할 값>)

df.where(df["Salary"] < 6000, np.nan)

실행결과

이번에는 Salary가 6000 미만인 데이터들만 살아남고, 나머지 데이터는 모두 NaN값으로 바뀌었습니다.

데이터 필터링 하기

마스킹이 일부 데이터를 가리는 거였다면 필터링은 내가 원하는 조건을 가진 데이터를 추출할 때 사용합니다. 필터링에는 별다른 메소드가 따로 있지는 않고, 1편에서 다뤘던 인덱싱을 이용하면 됩니다.

df.loc[<조건>]

다양한 케이스를 통해 사용법을 알아보겠습니다.

1. Salary가 5000 이상인 데이터만 필터링

df.loc[df["Salary"] >= 5000]

실행결과

2. Salary가 5000이상 7000 미만인 데이터만 필터링

두 개 이상의 조건을 조합할 때는 각각의 조건을 소괄호로 묶고, &|을 써주시면 됩니다. &는 모든 조건이 참이 되어야 True이고, |는 한 가지 조건만 참이 되어도 True입니다.

df.loc[(df["Salary"] >= 5000)&(df["Salary"] < 7000)]

실행결과

2. Salary가 5000 이상 또는 WeeklyExercise가 4 미만인 데이터만 필터링

df.loc[(df["Salary"] >= 5000)|(df["WeeklyExercise"] < 4)]

실행결과

정렬하기

이번에는 데이터를 정렬하는 법에 대해서 알아보겠습니다.

인덱스 기준 정렬

sort_index메소드를 통해서 인덱스를 기준으로 정렬할 수 있습니다.

df.sort_index()

실행결과

인자로 ascending=False를 넣어주면 내림차순으로 정렬할 수 있습니다.

 df.sort_index(ascending=False)

실행결과

컬럼 기준 정렬

컬럼 기준으로 정렬을 할 때는 sort_values 메소드를 사용합니다.

df.sort_values("Salary", ascending=False)

실행결과

여러 개의 컬럼을 기준으로 삼을 수도 있습니다.

df.sort_values(["WeeklyExercise", "WeeklyDrink"], ascending=False)

실행결과

함수를 통해 새로운 데이터 만들기

데이터를 다루는 작업을 하다 보면, 각 데이터에 특정한 함수를 적용하여 새로운 데이터를 만들어야 하는 경우가 많습니다. 주식으로 예를 든다면 주가 데이터를 활용해서 기술적 분석 지표를 만들어 낼 수 있습니다. 이럴 때는 apply 메소드를 활용할 수 있습니다. apply 메소드는 각 데이터를 순회하면서 정의된 함수를 적용하여 새로운 데이터를 만들어내는 메소드입니다.

단, apply함수를 사용하시기 전에 꼭 하고자 하는 기능을 pandas API에서 제공하고 있는지를 먼저 알아보시길 추천드립니다. apply는 기본적으로 데이터를 순회하는 방식이기 때문에 데이터가 많을수록 연산 시간이 비례해서 증가합니다. pandas API에서 이미 제공하고 있는 메소드의 경우에는 대부분 벡터 연산으로 처리되기 때문에 훨씬 더 빠른 시간에 원하는 결과를 얻으실 수 있습니다.

일반적인 함수를 통해 새로운 데이터 만들기

Address 컬럼의 데이터를 변경하여 새로운 주소체계를 만들어봅시다. 먼저 아래와 같은 함수를 정의해줍니다. 아래 함수는 주소를 인자로 받아서 해당 주소를 띄어쓰기 기준으로 제일 앞 단어만을 추출해 재조합한 결과를 리턴합니다.

def convert_address(address):
    splitted = address.split()
    first_characters = [each[0] for each in splitted]
    return "".join(first_characters)

apply메소드 안에 해당 함수를 인자로 넣어줍니다.

df["NewAddress"]  = df["Address"].apply(convert_address)
df.head(10)

실행결과

NewAddress라는 이름으로 새로운 컬럼이 생겼으며 함수가 잘 적용된 것을 보실 수 있습니다.

위에서는 Series 타입에 apply를 적용했는데, 이번에는 DataFrame 타입에 적용해보겠습니다. DataFrame의 경우 apply에 들어가는 함수가 데이터의 '행' (axis=1)이나 '열' (axis=0)을 인자로 받습니다. 아래 예제에서는 각 행을 인자로 받아서 건강상태 여부를 체크하는 간단한 함수를 만들었습니다.

def is_healthy(row):
    if row["WeeklyDrink"] < 2:
        return True
    elif row["WeeklyDrink"] < 5 and row["WeeklyExercise"] > 2:
        return True
    elif row["WeeklyExercise"] > 4:
        return True
    else:
        return False

마찬가지로 apply에 함수를 넣어줍시다.

df["is_healthy"] = df.apply(is_healthy, axis=1)
df.head(10)

실행결과

lambda 함수를 정의해 새로운 데이터 만들기

간단한 함수 같은 경우에는 lambda 함수를 정의할 수도 있습니다. lambda 함수에 대해 자세히 알고 싶으신 분들은 이 블로그 포스트를 참고해주세요.

df["Age"].apply(lambda x: (x // 10)*10)

실행결과

데이터 그룹화 하기

이번에는 데이터를 그룹화하는 방법에 대해서 알아보겠습니다. 데이터를 다루시다 보면 특정 그룹에 따른 통계치를 보고 싶을 때가 있습니다. 이럴 때는 groupby 메소드를 사용하면 됩니다.

Index 기준으로 그룹화

Index 기준으로 그룹화할 때는 groupby 메소드의 인자로 level을 명시해주어야 합니다. level은 0부터 시작하는 숫자입니다. 인덱스가 1개일 때 (일반적인 경우)는 level=0을 적어주시면 되고, Index가 여러 개인 경우 (MultiIndex)에는 그룹화를 원하는 기준의 Index level을 명시해주시면 됩니다. (세 번째 인덱스를 기준 : level=2)

아래는 WeeklyDrink를 인덱스로 지정하고, 해당 인덱스를 기준으로 Age와 Salary의 중간값을 보는 예제입니다.

df.set_index("WeeklyDrink").groupby(level=0)[["Age", "Salary"]].median()

실행결과

Column 기준으로 그룹화

Column 기준으로 그룹화하기 위해서는 groupby 메소드의 인자로 해당 컬럼의 명을 써주면 됩니다.

df.groupby(["Gender"]).mean()

실행결과

함수를 이용한 그룹화

groupby를 함수를 기준으로 할 수도 있습니다. 이때, 함수의 인자로는 index가 들어오게 됩니다. 함수로 그룹화를 할 때는 함수의 리턴 값이 같은 경우를 기준으로 그룹화됩니다.

현재 인덱스인 username의 제일 앞글자를 리턴하는 함수를 만들어보겠습니다.

def groupby_alphabet(index):
    return index[0]

이 함수의 리턴 값을 기준으로 그룹화하기 위해서는 해당 함수를 groupby의 인자로 넣어주시면 됩니다.

df.groupby(groupby_alphabet)[["Salary", "WeeklyExercise", "Age"]].mean()

실행결과

마치며...

이상으로, '자주쓰는 명령어로 배우는 Pandas' 시리즈를 마치도록 하겠습니다. 제가 다루지 않은 명령어도 굉장히 많습니다. 이럴 때는 구글링을 하시거나 Pandas 공식 문서를 찾아보시면 됩니다. 비록 공식문서가 영어이기는 하지만, 굉장히 이해하기 쉽게 작성이 되어있습니다. 구글 번역기를 돌리셔도 이해가 잘 되시리라 생각합니다.

이 시리즈가 많은 분들께 도움이 됐으면 좋겠습니다. 감사합니다.

반응형