ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Pandas 데이터 먼징 실습 1 - Null/Outlier 처리 및 데이터타입 변환
    데이터 분석/Pandas 2020. 8. 24. 11:44

    이 글은 <파이썬 데이터 사이언스 핸드북> p. 202 에 포함되어 있는 출생률 데이터 를 기준으로 작업한 것입니다.
    포스트에서 사용되는 데이터는 주피터 노트북에서 아래 링크를 통해 다운받으실 수 있습니다. 

    !curl -0 https://raw.githubusercontent.com/jakevdp/data-CDCbirths/master/births.csv --output ./births.csv

     

    사전에 필요한 프레임워크를 임포트합니다.
    그리고 필요한 데이터를 가져와서 데이터프레임 객체로 할당합니다. 

    import numpy as np
    import pandas as pd
    
    births = pd.read_csv('./births.csv')

     

    이러면 실습 준비 완료!
    지금부터 낯선 데이터에 대해서 데이터먼징하는 작업을 차근차근 살펴보겠습니다. :D 

     

    목차

    1. 데이터 요약 확인
    2. 널값 NULL 처리
    3. 이상치 Outlier 처리
    4. 데이터타입 확인 및 변환

     


    1. 데이터 요약 확인

     

    births.head()

    - 인덱스: 암묵적 인덱스 (auto-incremental)
    - 컬럼: year, month, day, gender, births

    year, month, births 는 np.number, int64 이고
    day 는 np.number, float64,
    gender 는 np.object, object 이다. 

     

    births.describe()

    births 데이터셋에 대한 np.number 데이터타입의 기술통계를 보여준다. 
    births.describe(include=np.number) 와 동일한 결과를 출력한다. 

     

    year 1969 ~ 2008년 기간내 일자(year, month, day) 별 출생률 데이터임을 알 수 있다.

    여기서 데이터의 이상한 부분을 찾아낼 수 있다:
    1) day 데이터는 왜 15067 개로 다른 데이터들보다 크기가 작을까?  
    2) day 데이터에 어떻게 99 가 있을 수 없는데?
    3) births 의 size 의 이상치 min 1 / max 199622 가 이상하다!

     

    births.describe(include=object) 를 출력하면 object 데이터타입을 가지는 칼럼값 gender, decade 에 대해서도 기술통계를 출력한다. 

     

    pandas.DataFrame.describe

    기본적인 기술통계 데이터를 보여준다. 
    기술통계는 데이터셋의 중심 경향, 분산, 분포를 요약하며, 이 때, NaN 값을 제외하고 요약한다. 
    숫자형과 객체형 Series, 이종의 데이터타입 컬럼으로 엮인 DataFrame 에 대해 분석한다. 결과는 입력값 따라 다양하다.

    Generate descriptive statistics.

    Descriptive statistics include those that summarize the central tendency, dispersion and shape of a dataset’s distribution, excluding NaN values. Analyzes both numeric and object series, as well as DataFrame column sets of mixed data types. The output will vary depending on what is provided. 

     

     

     

     

     

    2. NULL 처리

    여기서 데이터의 이상한 부분을 찾아낼 수 있다:
    1) day 데이터는 왜 15067 개로 다른 데이터들보다 크기가 작을까?  
    2) day 데이터에 어떻게 99 가 있을 수 없는데?
    3) births 의 size 의 이상치 min 1 / max 199622 가 이상하다!

     

    births.isnull().sum()

    pandas.DataFrame.isnull() : NULL 여부에 대한 마스킹 DataFrame 을 반환한다.
    pandas.DataFrame.isnull().sum() : NULL 여부에 대한 마스킹 DataFrame 에서 True 를 1 로, False 를 0 으로 간주하고 sum 한다.

    일자가 제대로 기록되지 않은 데이터는 일자별 데이터를 출력할 때 제거해야 한다.

     

    births.notnull()

    births = births[births['day'].notnull()]

    pandas.DataFrame.notnull(): Not NULL  여부에 대한 마스킹 DataFrame 을 반환한다. 
    Not NULL 데이터만 births 에 재할당한다. 15067 개만 남았다!

     

     

     

     

     

     

    3. 이상치 Outlier 처리

    여기서 데이터의 이상한 부분을 찾아낼 수 있다:
    1) day 데이터는 왜 15067 개로 다른 데이터들보다 크기가 작을까?  
    2) day 데이터에 어떻게 99 가 있을 수 없는데?
    3) births 의 size 의 이상치 min 1 / max 199622 가 이상하다!

     

    births 값에 대해서 시그마 클리핑 연산을 수행한다. 이러한 이상치 데이터를 한번에 제거하는 쉬운 방법이다!

    quartiles 4분위값을 계산한 후에,  시그마 계산을 위해 mu 와 sig 를 설정한다.
    이 부분은 다분히 통계적인 지식이 있어야하므로, 그대로 받아적었다. +_+!

    시그마 클리핑 연산을 완료하면 15067 개에서 14610 개로 축소된 데이터를 확인할 수 있다. 
    (암묵적인덱스를 다시 인덱싱하지는 않는가보다. 14610 개 크기의 데이터셋으로 축소되었는데도, 데이터의 마지막 인덱스 값이 15066 인 것을 보아선-) 

     

     

     

     

     

     

    4. 데이터 타입 확인 및 변환

    이상치 처리가 완료되었다. 이제 데이터는 문제없을듯!
    이제 데이터를 다루기 위해서 데이터타입을 정리한다. 특정 열의 데이터에 대해 데이터타입을 변환한다. 

     

    births.dtypes

    우선 데이터셋의 컬럼 단위 데이터타입을 확인한다. 

    pandas.DataFrame.dtypes
    DataFrame 객체의 데이터타입 확인용 프로퍼티

    DataFrame 내 각 칼럼의 데이터타입에 대한 정보를 Series 객체로 반환한다. columns 이름이 결과값의 index 가 된다. 여러 데이터타입이 섞여있는 컬럼값의 경우에는 'object' 로 반환한다. 

    property DataFrame.dtypes Return the dtypes in the DataFrame
    This returns a Series with the data type of each column. The result’s index is the original DataFrame’s columns. Columns with mixed types are stored with the object dtype.

     

     

    births.loc[:, 'year'] = births['year'].astype(int) 

    데이터타입을 변환하고 싶을 경우, 형변환처리하고 재할당한다.
    astype 은 copy 복사본 시리즈 객체 or 데이터프레임 객체를 반환한다. 
    births.loc[:, 'day'] 제한된 범위에, 동일한 크기의 시리즈 객체를 재할당한다. 

     

    사실 이렇게, 여러 컬럼값에 대해서 한번에 형변환을 처리할 수도 있다!

     

    pandas.DataFrame.astype()
    Cast a pandas object to a specified dtype dtype.

    pands 객체에 대하여 특정 데이터타입으로 형변환할 때 사용한다.
    copy 가 True 이므로, 유의하자.  만약 형변환이 호환되지 않는 경우 디폴트로 error 를 뱉는다. 

    dtype: 
    data type, or dict of column name -> data type
    copy: copyReturn a copy when copy=True, default True 
    errors {‘raise’, ‘ignore’}, default ‘raise’

     

    내가 겪은 경고 & 에러 정리

     

    births['day'] = births['day'].astype(int)

    에러는 아니지만, 경고가 발생한다. astype 은 copy 가 default True 이기 때문에 원본 데이터가 훼손될 수 있다. 
    이 때문에 SettingWithCopyWarning 경고 를 출력한다.
    일부 데이터에 대해서 할당할 때에는 .loc 으로 접근범위를 명시해주자!


    <ipython-input-77-c0836f9326e7>:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy births['decade'] = births['decade'].astype(int)


     

     

    births.loc[:, 'year'] = births.loc[:, 'year'].astype(int)

    copy 를 잘 이해하지 못해서 생기는 문제 ㅠㅠ 
    원본 접근대상 = 값 공식을 기억하자.  Try using .loc[row_indexer,col_indexer] = value


    /Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pandas/core/indexing.py:966: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_indexer,col_indexer] = value instead See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy self.obj[item] = s


     

     

    위 유의사항을 다 지켰는데에도 이런 에러값이 나온다면, 데이터에 None 이나 NaN 값이 있는 것이다.  
    None 이나 NaN 에 대해서는 형변환이 실패하기 때문! Null 처리를 잘 했는지 다시 확인하고 오자.


    ValueError: Cannot convert non-finite values (NA or inf) to integer


     


    여기까지 기초적인 Data Munging 을 해보았습니다. 

    다음 글에서는 정제된 데이터를 가지고 추가 가공을 해볼 예정 +__+b

    댓글

Designed by Tistory.