[Pandas] DataFrame 결측치(NaN) 처리

반응형
    반응형

    데이터를 수집하면 전산오류나 사람의 실수로 결측치가 발생하게 됩니다.

    특히 외부에서 데이터를 가져오면 더욱 그럴 수 밖에 없는데 

    결측치를 방치하고 알고리즘에 데이터셋을 넣게 되면 아무리 좋은 알고리즘이라도 성능이 떨어지고

    엉뚱한 결론에 도달할 수도 있습니다. 돈과 관련된 것이라면 아주 치명적인 결과를 만들수도 있습니다.

    따라서 본격적인 분석을 하기 전에 결측치를 먼저 처리하는 과정이 필요합니다.

    결측치를 처리하는 방법을 몇 가지 소개하겠습니다.

     

     

    먼저 간단한 DataFrame을 만들겠습니다.

    import numpy as np
    import pandas as pd
    r1 = [1,np.nan,2,3]
    r2 = [4,5,np.nan,6]
    r3 = [7,8,9,np.inf]
    
    df = pd.DataFrame({'r1':r1,'r2':r2,'r3':r3})
    df

     

     

     

     

    결측치 확인

    데이터가 크다면 결측치가 있는지 확인해봐야합니다.

    있다면 처리를 해야겠지요.

     

    결측치를 확인하는 방법부터 소개하겠습니다. 3가지 방법이 있습니다.

     

    1. isna()
    2. isnull
    3. isin

     

     

    isna()

    isna() 함수를 호출하면 NaN 값 포함 여부를 Boolean 타입의 값으로 반환합니다. 

    df.isna()

     

     

     

    결측치 갯수를 알고 싶다면 다음과 같이 합니다.

    df.isna().sum()

     

     

    각 column 별로 몇개의 결측치가 있는지 알려줍니다.

     

    isnull()

    isna() 와 같습니다. 이건 판다스가 R의 영향을 받은 이유이기도 한데 

    R에서는 na 와 null 이 다른 데이터로 구분하기 때문에 그렇습니다.

    두 데이터를 넘파이의 NaN으로 대체해 구분이 없어진 것 뿐입니다.

    df.isnull()

     

     

     

    df.isnull().sum()
    

     

     

    마찬가지 방법으로 결측치를 찾을 수 있습니다.

     

    isin()

    저는 isin()을 많이 쓰는 것 같습니다. isin() 함수가 해당 데이터의 존재여부를 묻는 함수라서 내가 찾고자 하는 데이터의 존재여부를 물을 수 있습니다. 그러다보니 다양하게 데이터가 아니거나 불필요한 것들도 찾을 수 있습니다.

    이런 걸 이상치라고 하는데 isin()을 쓰면 결측치는 물론이고 이상치의 데이터 존재여부를 알 수 있습니다.

    코드 방식은 isna(),isnull()과 유사하고 한가지 주의할 점은 isin()은 파라미터 값에 항상 리스트를 넣어야 작동을 합니다. 

    df.isin([np.nan,np.inf])

     

    df.isin([np.nan,np.inf]).sum()

     

    결측치 처리(버리기)

    결측치가 있는 row나 column을 버리는 방법입니다. 

    dropna를 쓰면 결측치만 없어지고 drop으로 설정을 해야 이상치가 사라집니다.

     

    row 제거

    dropna를 이용해 결측치가 있는 부분을 제거할 수 있는데 dropna의 디폴트 축은 row로 되어있어서 axis 요청이 따로 없으면 row를 제거합니다. 

    아래 세 개중 아무거나 해도 똑같은 결과가 나옵니다.

    df.dropna()
    df.dropna(axis='rows')
    df.dropna(axis=0)

     

    column 제거

    결측치가 있는 column을 제거하려면 axis='columns' 또는 axis=1 을 dropna 괄호 안에 넣습니다.

    df.dropna(axis='columns')
    df.dropna(axis=1)

     

    이상치 제거

    이상치를 제거하려면 drop으로 명명해주어야 합니다.

    index로 row를 제거합니다.

    search_df = df[df.isin([np.inf]).any(1)]
    df.drop(search_df.index,axis=0)

     

    column을 제거하고 싶다면 search_df.T 로 column와 row를 변환시킨 후 다시 inf가 있는 row를 찾아서 drop합니다.

    복잡합니다. 간단한 방법을 알고 싶은데 알 수가 없네요 ㅜ 

     

    search_col = search_df.T[search_df.T.isin([np.inf]).any(1)].index
    df.drop(search_col,axis=1)

     

    결측치 처리(채우기)

    결측치는 판다스에서 처리하는 기능이 꽤 있습니다. 이상치는 rename이나 drop으로 다 없애버리는 방법 안에서 해결이 됩니다. 

    그런데 drop으로 결측치를  없애려고 하면 결측치를 없애기 위해 column과 row 전체를 없애야 하니 정보 손실이 큽니다. 그래서 drop으로 row, column 전체를 버리지 말고 결측치를 채우는 방법만 설명하겠습니다.

    4가지 방법이 있습니다.

    1. 앞선 행의 값을 가져온다 (pad/ffill)
    2. 다음 행의 값을 가져온다 (bfill/backfill)
    3. 내가 원하는 값을 넣는다.
    4. 보간법(interpolation)을 이용한 값채우기(interpolate)

    pad/ffill

    앞선 행의 값으로 NaN을 채워보겠습니다. method = 'pad' 또는 method= 'ffill' 를 넣으면 됩니다.

    pad만 보이겠습니다.

    df.fillna(method='pad')

     

    bfill/backfill

    이번엔 뒤의 행의 값을 가져오겠습니다. method = 'bfill' 또는 method='backfill' 입니다.

    df.fillna(method='bfill')

     

    원하는 값 넣기

    df.fillna(10.0)

     

    보간법 활용

    보간법은 데이터와 데이터 사이에 값에 빈 곳에 임의의 점을 추가해서 데이터를 이어주는 방법인데

    어떤 그래프로 표현할것인지에 따라 채워주는 값이 달라집니다.

    여기서는 기본값인 linear로 하겠습니다. line을 그린다는 생각으로 데이터를 추가하는 방법입니다.

    보간법에 대한 자세한 방법은 수치해석을 공부하시면 알 수 있습니다.

    여기는 결측치 제거를 위한 포스팅이니 자세한 방법론은 생략하겠습니다.

    df.interpolate(method='linear',limit_direction='forward')

     

     

    limit_direction = 'forward' 는 위에서 밑으로 하는 방향으로 결측치를 채워나가겠다는 얘기입니다.

    기본값은 이렇게 되어 있습니다. 이것 말고도 'backward', 'both' 가 있습니다.

    interpolate는 방법이 여러가지여서 소개만 하고 여기서 마치겠습니다.

    interpolate의 관한건 따로 포스팅을 하겠습니다.

     

     

    관련 포스팅

    [Python/Pandas] - [Pandas]데이터프레임 로우와 컬럼 바꾸기(df.T)

     

    댓글

    Designed by JB FACTORY

    ....