[python] 데이터 전처리 ②

     

    순서대로 정렬하기

     

    df.sort_values( )에 정렬 기준으로 삼을 변수를 입력한다.

    높은 값에서 내림차순으로 정렬할 시, ascending = False를 입력한다. 

     

    exam.sort_values('math')    # math 오름차순 정렬
    
    exam.sort_values('math', ascending = False)   # math 내림차순 정렬

     

    정렬 기준으로 삼을 변수를 여러 개 지정하려면 [ ] 안에 변수명을 나열하면 된다. 변수별로 정렬 순서를 다르게 지정하려면 ascending에 [ ]를 이용해 값을 입력한다. True를 입력하면 오름차순, False를 입력하면 내림차순으로 정렬한다. 

     

    # nclass는 오름차순, math는 내림차순으로 정렬
    exam.sort_values(['nclass', 'math'], ascending = [True, False])

    # 실습 QUIZ 풀이 (혼자서 해보기)

     

    # mpg 데이터를 이용해 분석 문제를 해결
    # 'audi'에서 생산한 자동차 중에서 어떤 자동차 모델의 hwy(고속도로 연비)가 높은지 알아보려고 한다. 'audi'에서 생산한 자동차 중 hwy가 1~5위에 해당하는 자동차의 데이터를 출력하라.
    
    mpg_audi = mpg.query('manufacturer == "audi"')
    mpg_audi.sort_values(['hwy'], ascending = False).head()

    query( )를 이용해 'audi'에서 생산한 자동차만 추출, sort_values( )로 hwy를 기준으로 내림차순 정렬한다. 

    1~5위에 해당하는 데이터를 출력하라고 했음으로 head( )를 이용한다. 

     

    두 줄의 코드를 한 번에 작성하면 다음과 같이 쓸 수 있다. 결과는 같다. 

    mpg.query('manufacturer == "audi"').sort_values('hwy', ascending = False).head()

     


     

    파생변수 추가하기

     

    데이터에 들어 있는 변수 이외에 변수를 조합하거나 함수를 이용해 새 변수를 만들 수 있다. 

    이때, df.assign( )을 이용하면 파생변수를 생성할 수 있다.

    새로 만들 변수명에는 따옴표를 사용하지 않으니 이 점을 주의해야한다.

     

    # total이라는 새로운 변수명에는 따옴표 사용하지 않는다.
    exam.assign(total = exam['math'] + exam['english'] + exam['science'])
    
    # 여러 파생변수를 한 번에 추가할 때는 쉼표를 사용하면 된다.
    exam.assign(
        total = exam['math'] + exam['english'] + exam['science'],
        mean = (exam['math'] + exam['english'] + exam['science'])/3)

     

    df.assign( )에 NumPy 패키지의 where( )를 적용하면 조건에 따라 다른 값을 부여한 변수를 추가할 수 있다.

     

    import numpy as np
    exam.assign(test = np.where(exam['science'] >= 60, 'pass', 'fail'))

     

    변수를 추가하고 나면 이어지는 pandas 함수에 바로 활용할 수 있다. 

    # total 변수를 추가하고, sort.values( )를 활용하여 total 변수 기준으로 정렬한다. 
    exam.assign(total = exam['math'] + exam['english'] + exam['science']).sort_values('total')

     

    df.assign( )을 사용할 때 변수명 앞에 데이터 프레임명을 반복해야한다. 

    이는 lambda를 이용해 프레임명이 아닌 약어를 입력해 코드를 간결하게 작성할 수 있다. 

    lambda x : 는데이터 프레임명 자리에 x를 입력하겠다는 의미다. 

    # 긴 데이터 프레임명 지정
    long_name = pd.read_csv('exam.csv')
    
    # long_name 직접 입력할 때의 코드
    long_name.assign(new = long_name['math'] + long_name['english'] + long_name['science'])
    
    # lambda를 이용해 간결하게 만든 코드
    long_name.assign(new = lambda x : x['math'] + x['english'] + x['science'])

     

    앞에서 만든 파생 변수를 이용해 다시 파생 변수를 만드는 경우, lambda를 이용해 데이터 프레임명을 약어로 입력해야한다. 

    # 파생변수 total을 가지고 다시 파생변수 mean을 만들 때 lambda를 쓰지 않으면 에러가 출력된다.
    exam.assign(total = exam['math'] + exam['english'] + exam['science'],
               mean = lambda x : x['total'] / 3)
               
     # 가독성을 위해 파생변수를 만드는 행에 lambda를 각각 입력하면 데이터 프레임명을 통일할 수 있다.
     exam.assign(total = lambda x : x['math'] + x['english'] + x['science'],
               mean = lambda x : x['total'] / 3)

     


    # 실습 QUIZ (혼자서 해보기)

     

    # mpg 데이터는 연비를 나타내는 변수가 hwy(고속도로 연비), cty(도시 연비) 두 종류로 분리되어 있다. 두 변수를 각각 활용하는 대신 하나의 합산 연비 변수를 만들어 분석하려 한다. 
    # 1. mpg 데이터 복사본을 만들고, cty와 hwy를 더한 '합산 연비 변수'를 추가하라.
    
    import pandas as pd
    mpg = pd.read_csv('mpg.csv')
    mpg_new = mpg.copy()
    
    mpg_new = mpg_new.assign(total = mpg_new['hwy'] + mpg_new['cty'])
    
    # 2. 앞에서 만든 '합산 연비 변수'를 2로 나눠 '평균 연비 변수'를 추가하라. 
    mpg_new = mpg_new.assign(mean = mpg_new['total'] / 2)
    
    # 3. '평균 연비 변수'가 가장 높은 자동차 3종의 데이터를 출력하라.
    mpg_new.sort_values('mean', ascending = False).head(3)
    
    # 4. 1~3번 문제를 해결할 수 있는 하나로 연결된 pandas 구문을 만들어 실행하라. 데이터는 복사본 대신 mpg 원본을 이용하라.
    mpg.assign(total = lambda x : x['cty'] + x['hwy'], 
               mean = lambda x : x['total'] / 2) \
       .sort_values('mean', ascending = False)   \
       .head(3)

     


     

    집단별로 요약하기

     

    각 집단을 요약한 값을 구할 때는 df.groupby( )와 df.agg( )를 사용한다. 

    df.agg( )에 요약값을 할당할 변수명과 =를 입력한 다음, 값을 요약하는데 사용할 변수와 함수를 괄호 안에 나열한다.

     

    # math 평균 구하기
    exam.agg(mean_math = ('math', 'mean'))

     

    ▶ 요약값을 할당할 변수명은 df.assign( )을 사용할 때와 마찬가지로 자유롭게 정하고, 따옴표는 입력하지 않는다.

    ▶ 요약하는데 사용할 변수명과 함수명은 따옴표로 감싸 문자 형태로 입력하고, 함수명 뒤에 ( )를 입력하지 않는다.

     

    집단별로 요약 통계량을 구하고 싶다면 df.groupby( )로 변수를 지정해 변수의 범주별로 데이터를 분리한 다음, agg( )를 적용하면 된다. 

     

    # nclass별로 분리하고 math의 평균을 구한다. 
    exam.groupby('nclass').agg(mean_math = ('math', 'mean'))

    출력 결과는 위와 같다. 표의 맨 첫 번째 행이 무엇인가 이상해보인다. 이는 집단을 나타낸 변수명 nclass가 인덱스로 바뀌어 mean_math보다 밑에 표시되었기 때문이다. groupby( )의 기본값이 변수를 인덱스로 바꾸도록 설정되어 있기 때문에 그렇다. df.groupby( )에 as_index = False를 입력하게 되면 변수를 인덱스로 바꾸지 않는다. 

     

    +) index : 값이 데이터 프레임의 어디에 있는지 '값의 위치를 나타낸 값' 이다.

    exam.groupby('nclass', as_index = False).agg(mean_math = ('math', 'mean'))

     

     

    여러 요약 통계량을 한 번에 구하고 싶다면 df.assign( )으로 여러 변수를 한 번에 추가하는 것과 마찬가지로 코드를 입력하면 된다. 

     

    exam.groupby('nclass') \
        .agg(mean_math   = ('math', 'mean'),
             sum_math    = ('math', 'sum'),
             median_math = ('math', 'median'),
             n           =  ('nclass', 'count'))

     

    모든 변수의 요약 통계량을 한 번에 구하고 싶다면 df.groupby( )에 agg( ) 대신 mean( )이나 sum( )과 같은 요약 통계량 함수를 적용하면 데이터 프레임에 들어 있는 모든 변수의 요약 통계량을 한 번에 구할 수 있다.

    exam.groupby('nclass').mean()

     

    +) agg( )에 자주 사용하는 요약 통계량 함수

    함수 통계량
    mean( ) 평균
    std( ) 표준편차
    sum( ) 합계
    median( ) 중앙값
    min( ) 최소값
    max( ) 최대값
    count( )  빈도(개수)

     

     

    groupby( )에 여러 변수를 지정해 집단을 나눈 다음 다시 하위 집단으로 나눌 수 있다. 

    # 다음은 제조 회사별로 집단을 나누고 다시 구동 방식별로 나누어 도시 연비 평균을 구한 코드다.
    
    mpg.groupby(['manufacturer', 'drv']) \
       .agg(mean_cty = ('cty', 'mean'))

     

    출력 결과에서 drv 행의 개수가 제조 회사별로 다른 이유는 회사마다 생산한 drv 종류가 다르기 때문이다. 

     

    # audi는 drv를 2종 생산, chervorlet은 drv를 3종 생산했음을 보여주는 코드
    
    mpg.query('manufacturer == "audi"') \
       .groupby(['drv']) \
       .agg(n = ('drv', 'count'))
       
      
    mpg.query('manufacturer == "chervorlet"') \
       .groupby(['drv']) \
       .agg( n = ('drv', 'count'))

     

    집단별로 빈도를 간단하게 구하고 싶다면 df.value_counts( )를 이용하면 된다. 데이터 프레임에서 빈도를 구할 변수를 추출한 후, value_counts( )를 적용하면 된다. 

     

    mpg['drv'].value_counts( )

     

    이는 짧은 코드로 빈도를 구할 수 있고 자동으로 빈도 기준으로 내림차순 된다는 장점이 있지만, 시리즈 자료 구조로 출력하기 때문에 query( )는 적용할 수 없다는 단점이 있다. 이때, 데이터 프레임으로 변환을 해야만 query( )를 사용할 수 있다. 

     

    mpg['drv'].value_counts( ) \
              .to_frame \
              .rename_axis('drv') \
              .query('n > 100')

     

    pandas 패키지의 함수들은 하나의 구문으로 조합해 분석 문제를 해결할 수 있다. 

     

    예를 들어. 제조  회사별로 'suv' 자동차의 도시 및 고속도로 합산 연비 평균을 구해 내림차순으로 정렬하고, 1~5위까지 출력하는 코드를 작성한다고 하자. 

     

    이 코드를 작성하기 위해서는 우선 순위를 정해야한다. 

    1. suv 추출 - query( )

    2. 합산 연비 변수 만들기 - assign( )

    3. 회사별 분리 - groupby( )

    4. 합산 연비 평균 구하기 - agg( )

    5. 내림차순 정렬 - sort_values( )

    6. 1~5위까지 출력 - head( )

     

    우선 순위대로 작성한 코드는 다음과 같다. 

    mpg.query('category == "suv"') \
       .assign(total = (mpg['hwy'] + mpg['cty']) / 2) \
       .groupby('manufacturer') \
       .agg(mean_tot = ('total', 'mean')) \
       .sort_values('mean_tot', ascending = False) \
       .head()

     


     

    #실습 QUIZ (혼자서 해보기)

     

    # 1. mpg 데이터의 category는 자동차를 특징에 따라 'suv', 'compact' 등 일곱 종류로 분류한 변수다. 어떤 차종의 도시 연비가 높은지 비교해보려고 한다. catgory별 cty 평균을 구해라.
    
    mpg.groupby('category') \
       .agg(mean_cty = ('cty', 'mean'))
       
    # 2. 앞 문제의 출력 결과는 category 값 알파벳순으로 정렬되어 있다. 어떤 차종의 도시 연비가 높은지 쉽게 알아볼 수 있도록 cty 평균이 높은 순으로 정렬해 출력하라.
    
    mpg.groupby('category') \
       .agg(mean_cty = ('cty', 'mean')) \
       .sort_values('mean_cty', ascending = False)
       
    # 3. 어떤 회사 자동차의 hwy(고속도로 연비)가 가장 높은지 알아보려고 한다. hwy 평균이 가장 높은 회사 세 곳을 출력하라.
    
    mpg.groupby('category') \
       .agg(mean_hwy = ('hwy', 'mean')) \
       .sort_values('mean_hwy', ascending = False).head(3)
       
    # 4. 어떤 회사에서 'compact' 차종을 가장 많이 생산하는지 알아보려고 합니다. 회사별 'compact' 차종 수를 내림차순으로 정렬해 출력하라.
    
    mpg.query('category == "compact"') \
       .groupby('manufacturer') \
       .agg(n = ('manufacturer', 'count')) \
       .sort_values('n', ascending = False)
       
    # 4번 문제의 코드를 짧게 표현한 코드는 다음과 같다.
    mpg.query('category == "compact"') \
       .value_counts('manufacturer')

     


     

    데이터 합치기

     

    1. 가로로 합치기 -  pd.merge( )를 이용한다.

    ① pd.merge( )에 결합할 데이터 프레임명을 나열한다.

    ② 오른쪽에 입력한 데이터 프레임을 왼쪽 데이터 프레임에 결합하도록 how = 'left'를 입력한다. 

    ③ 데이터를 합칠 때 기준으로 삼을 변수명을 on에 입력한다. 

     

    import pandas as pd
    
    test1 = pd.DataFrame({'id' : [1, 2, 3, 4, 5],
                          'midterm' : [60, 80, 70, 90, 85]})
    
    test2 = pd.DataFrame({'id' : [1, 2, 3, 4, 5],
                          'final' : [70, 83, 65, 95, 80]})

     

    total = pd.merge(test1, test2, how = 'left', on = 'id')
    total

     

     

     

    다른 데이터를 활용해 변수를 추가하고 싶다면 pd.merge( )를 활용하면 된다.

    name = pd.DataFrame({'nclass' : [1, 2, 3, 4, 5],
                         'teacher' : ['kim', 'lee', 'park', 'choi', 'jung']})
    name

     

    nclass와 teacher 두 변수로 구성되어 있는 name을 exam 데이터 프레임에 추가하면 다음과 같이 출력된다. 

    exam_new = pd.merge(exam, name, how = 'left', on = 'nclass')
    exam_new

     

    nclass 변수 기준으로 두 데이터 프레임이 합쳐진 것이다. 

     

     

    2. 세로로 합치기 - pd.concat( )을 사용한다. 

     

    group_a = pd.DataFrame({'id' : [1, 2, 3, 4, 5],
                            'test' : [60, 80, 70, 90, 85]})
    
    group_b = pd.DataFrame({'id' : [6, 7, 8, 9, 10],
                            'test' : [70, 83, 65, 95, 80]})

    group_all = pd.concat([group_a, group_b], ignore_index = True)
    group_all

    ignore_index 없이 출력하면 인덱스 0~4가 중복된 형태로 나오게 된다.

     

    데이터를 세로로 합칠 때는 두 데이터의 변수명이 같아야한다. 위 예시처럼 변수가 id, test로 이루어진 데이터 프레임 2개였기 때문에 합칠 수 있었던 것이다. 변수명이 같지 않다면 pd.rename( )을 활용하면 된다. 

     

     

     

     

    Reference

    김영우, 「DO IT! 쉽게 배우는 파이썬 데이터 분석」, 이지스퍼블리싱, 2022, p. 151-176

    댓글