[Python.TitanicOverview] 데이터 전처리 2 - 결측치 처리

2021. 2. 26. 05:00Python과 머신러닝/최종 실습 (Titanic Dataset)

1. 결측치 처리 예제

In [1]:import pandas as pd import numpy as np

In [2]:#https://chrisalbon.com/python/data_wrangling/pandas_missing_data/
       raw_data = {'first_name': ['Jason', np.nan, 'Tina', 'Jake', 'Amy'], 
                   'last_name': ['Miller', np.nan, 'Ali', 'Milner', 'Cooze'], 
                   'age': [42, np.nan, 36, 24, 73],
                   'sex': ['m', np.nan, 'f', 'm', 'f'],
                   'preTestScore': [4, np.nan, np.nan, 2, 3],
                   'postTestScore': [25, np.nan, np.nan, 62, 70]}
        df = pd.DataFrame(raw_data, columns = ['first_name', 'last_name', 'age', 'sex', 'preTestScore', 'postTestScore']) 
        df
Out[2]:

Out[2]

  • 이 데이터는 chrisalbon.com에서 가져온 예제이다.
  • Out[2]에 나온 것과 같은 데이터가 있다고 보자. 이 중 결측치가 많은데, 결측치 확인부터 코드로 하는 것이 가장 좋다. (매번 수많은 데이터를 직접 확인하기란 불가능하다)

 

2. 결측치의 비율(%) 확인하기

In [3]:df.isnull().sum() / len(df)*100 
Out[3]:first_name 20.0
       last_name 20.0
       age 20.0 
       sex 20.0 
       preTestScore 40.0
       postTestScore 40.0 
       dtype: float64
  • In[3]은 각 column/series별로 결측치가 존재하는 비율을 보기 위한 코드이다.
  • 이 한 줄의 코드로 어떤 X변수가 결측치가 많은지 한 번에 확인할 수 있고, 그에 따라 처리를 할 수 있을 것이다.

 

3. 결측치 처리방법 1 : X 변수 중 하나라도 결측치가 있다면 row 제거

In [4]:df.dropna()
Out[4]:

Out[4]

 

4. 결측치 처리방법 2 : X 변수가 전부 결측치일 경우에 row 제거

In [5]:df.dropna(how='all')
Out[5]:

Out[5]

  • how='all' : 모든 X변수가 NaN일 때만 row를 drop 한다

 

5. 결측치 처리방법 3 : X 변수가 전부 결측치일 경우에 column 제거

In [6]:df.dropna(axis=1, how='all')
Out[6]:

Out[6]

  • axis=1 : Column에 아무런 valid data가 없을 경우 (전부 NaN일 경우) Column을 제거한다.

 

 

6. 결측치 처리방법 4 : n개 미만의 X변수가 valid 하면 drop

In [7]:df.dropna(thresh=1)
Out[7]:

Out[7]

  • dropna(thresh=1)
    • 각 row별로 thresh 개수 이상의 valid data가 있을 경우에는 두고,
    • thresh 개수 미만의 valid data가 있을 경우에는 drop 한다.

 

7. 결측치 처리방법 5 : 데이터 채우기 (평균값으로 결측치 대체)

In [8]:cleaned_df = df.dropna(axis=1, how='all') 
       cleaned_df = df.dropna(axis=0, how='all') 
       cleaned_df

In [9]:fillna_df = cleaned_df.copy()
       fillna_df['preTestScore']=cleaned_df['preTestScore'].fillna(cleaned_df['preTestScore'].mean()) 
       fillna_df
Out[9]:

Out[8]
Out[9]

  • In[9]은 cleaned_df의 preTestScore의 결측치를 평균으로 대체하였고, 대체된 값을 fillna_df로 옮겼다
  • Out[9]에서 보다시피 Tina Ali의 PreTestScore가 NaN에서 3.0으로 변경된 것을 확인할 수 있다.
  • 결측치가 많지 않은 경우에는 이와 같이 평균값으로 결측치를 대체하는 것도 좋은 방법이다.

 

8. 결측치 처리방법 6 : 데이터 채우기 (그룹별 평균값으로 결측치 대체하기)

In [10]:cleaned_df.groupby('sex')['postTestScore'].mean()
Out[10]:sex 
        f 70.0
        m 43.5
        Name: postTestScore, dtype: float64

In [11]:fillna_df['postTestScore'] = cleaned_df['postTestScore'].fillna(cleaned_df.groupby('sex')['postTestScore'].transform('mean')) 
        fillna_df
Out[11]:

Out[11]

  • 결측치를 전체 평균으로 넣는 것이 잘못된 방식일 수도 있다.
  • 이럴 때에는 최대한 세분화된 분류에 따라서 분류별 평균을 적용하는 것이 좋다.
  • groupby 하여 그룹별 평균을 계산하고, 그룹별 평균으로 fillna를 하는 것이 한 단계 더 발전한 방법일 것이다.

 

9. Titanic 예제에서 결측치 채우기

In [11]:pd.options.display.float_format = '{:.2f}'.format

In [12]:df.isnull().sum() / len(df)*100
Out[12]:PassengerId 0.00 
        Pclass 0.00
        Name 0.00 
        Sex 0.00 
        Age 20.09 
        SibSp 0.00
        Parch 0.00 
        Ticket 0.00
        Fare 0.08
        Cabin 77.46
        Embarked 0.15
        dtype: float64

In [13]:df[df['Age'].notnull()].groupby(['Sex'])['Age'].mean()
Out[13]:Sex 
        female 28.69 
        male 30.59
        Name: Age, dtype: float64

In [14]:df[df['Age'].notnull()].groupby(['Pclass'])['Age'].mean()
Out[14]:Pclass 
        1 39.16
        2 29.51
        3 24.82
        Name: Age, dtype: float64

In [15]:df['Age'].fillna(df.groupby('Pclass')['Age'].transform('mean'), inplace=True)

In [16]:df.isnull().sum() / len(df)*100
Out[16]:PassengerId 0.00
        Pclass 0.00
        Name 0.00
        Sex 0.00 
        Age 0.00
        SibSp 0.00 
        Parch 0.00
        Ticket 0.00
        Fare 0.08 
        Cabin 77.46
        Embarked 0.15
        dtype: float64

  • In[12] : Titanic에서도 동일하게 결측치의 비율을 보면, Age의 결측치부터 처리가 필요해 보인다.
  • In[13] : Age의 평균을 Sex별로 보니 남녀 간의 차이가 크지 않다.
  • In[14] : Age의 평균을 Pclass별로 보니 차이가 더 명확하여, Pclass별 평균을 데이터에 적용하는 것이 더 유의미하고 판단할 수 있다.
  • In[15] : pclass별 평균을 갖고 df['Age']를 채워준다.
반응형