ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [CHAPTER 12] 데이터 분석 | pandas
    Deep Learning/인공지능 입문 코딩 2021. 6. 3. 18:18
    728x90

    pandas는 파이썬 데이터 처리를 위한 라이브러리이다. 데이터 분석과 같은 작업에서 필수적인 라이브러리이니 자세히 살펴보도록 하자.


    pandas의 특징

    빠르고 효율적이며 다양한 표현력을 갖춘 자료구조

    실세계 데이터 분석을 위해 만들어진 파이썬 패키지

    다양한 형태의 데이터에 적합

    이종(heterogeneous) 자료형의 열을 가진 테이블 데이터

    시계열 데이터

    레이블을 가진 다양한 행렬 데이터

    다양한 관측 통계 데이터

    핵심 구조

    시리즈(Series) : 레이블이 붙어있는 1차원 벡터

    데이터 프레임(DataFrame) : 행과 열로 되어있는 2차원 테이블, 각 열은 시리즈로 되어 있다.

     

     

    이들 데이터 구조는 모두 넘파이 배열을 이용하여 구현된다. 

    행의 이름을 Index

    열의 이름을 columns 라고 부른다.

     

     

     

     

     

     

     

     


    기본적인 사용법

    아래 데이터를 토대로 DataFrame을 만들어보자.

    이름 나이 성별 평점
    김수안 19 4.35
    김수정 23 4.23
    박동윤 22 4.45
    강이안 19 4.37
    강지안 16 4.25
    >>> import pandas as pd
    >>> import numpy as np
    
    >>> name_series = pd.Series(['김수안', '김수정', '박동윤', '강이안', '강지안'])
    >>> age_series = pd.Series([19, 23, 22, 19, 16])
    >>> sex_series = pd.Series(['여', '여', '남', '여', '남'])
    >>> grade_series = pd.Series([4.35, 4.23, 4.25, 4.37, 4.25])
    
    >>> df = pd.DataFrame({
    	'이름': name_series,
    	'나이': age_series,
    	'성별': sex_series,
    	'평점': grade_series})
        
    >>> df
        이름  나이 성별    평점
    0  김수안  19  여  4.35
    1  김수정  23  여  4.23
    2  박동윤  22  남  4.25
    3  강이안  19  여  4.37
    4  강지안  16  남  4.25

    각 열에 대한 데이터를 pd.Series()로 만들고

    Series를 기반으로 DataFrame()을 만든다.

    DataFrame()을 호출할 때 이름 나이 성별 평점을 key로 하고 series들을 value로 하는 딕셔너리를 인자로 전달해 준다.

     

    이미 만들어져 있는 csv파일을 읽어올 수도 있는데 그 방법을 살펴보자.

    먼저 '따라하며 배우는 파이썬과 데이터 과학'의 저자의 github에서 데이터 파일을 다운로드하여오자.

    https://github.com/dongupak/DataSciPy/blob/master/data/csv/countries.csv

    countries.csv

    pd.read_csv() 함수를 이용한다. 첫 번째 인자는 경로, index_col에 0을 넘겨주면 0번째 열이 인덱스로 사용된다.

    import pandas as pd
    
    countries_df = pd.read_csv('../data/countries.csv', index_col=0)
    print(countries_df)
    
       country      area     capital  population
    KR   Korea     98480       Seoul    51780579
    US     USA   9629091  Washington   331002825
    JP   Japan    377835       Tokyo   125960000
    CN   China   9596960     Beijing  1439323688
    RU  Russia  17100000      Moscow   146748600

    원하는 데이터 선택하기

    특정 열만 선택하려면 대괄호 안에 열의 이름을 넣어주면 된다.

    >>> countries_df['country']
    KR     Korea
    US       USA
    JP     Japan
    CN     China
    RU    Russia
    Name: country, dtype: object

     

    특정 행을 선택하려면 loc['index']를 이용한다.

    >>> countries_df.loc['KR']
    country          Korea
    area             98480
    capital          Seoul
    population    51780579
    Name: KR, dtype: object

     

    앞의 5행만 얻고 싶을 때는 head()를 사용한다. 뒤의 5행을 얻으려면 tail()을 같은 방식으로 사용하면 된다.

    데이터가 5행 밖에 없어서 차이가 없는 걸로 보인다.. ㅋ

    >>> countries_df.head()
       country      area     capital  population
    KR   Korea     98480       Seoul    51780579
    US     USA   9629091  Washington   331002825
    JP   Japan    377835       Tokyo   125960000
    CN   China   9596960     Beijing  1439323688
    RU  Russia  17100000      Moscow   146748600
    >>> countries_df.tail()
       country      area     capital  population
    KR   Korea     98480       Seoul    51780579
    US     USA   9629091  Washington   331002825
    JP   Japan    377835       Tokyo   125960000
    CN   China   9596960     Beijing  1439323688
    RU  Russia  17100000      Moscow   146748600

     

    슬라이싱을 이용할 수도 있다.

    >>> countries_df[:3]
       country     area     capital  population
    KR   Korea    98480       Seoul    51780579
    US     USA  9629091  Washington   331002825
    JP   Japan   377835       Tokyo   125960000

     

    위의 것들을 활용하여 써보자

    열과 행을 결합하여 선택할 수 있다.

    >>> countries_df['population'][:3]
    KR     51780579
    US    331002825
    JP    125960000
    Name: population, dtype: int64

     

    loc 함수에 행과 열의 레이블을 함께 써주면 특정한 요소 하나만 선택할 수 있다.

    >>> countries_df.loc['US', 'capital']
    'Washington'

     

     

    해당 열을 선택하고 loc함수로 행을 선택할 수도 있다.

    >>> countries_df['capital'].loc['US']
    'Washington'
    

     

    데이터 추가

    인구 밀도를 새로운 열로 추가하고 싶다.

    아래와 같이 하면 된다. 쉽다. 설명할 필요도 없는 듯

    import pandas as pd
    
    countries_df = pd.read_csv('../data/countries.csv', index_col=0)
    countries_df['density'] = countries_df['population'] / countries_df['area']
    
    print(countries_df)
    
         country         area           capital   population         density
    KR   Korea        98480            Seoul    51780579    525.797918
    US     USA     9629091   Washington   331002825      34.375293
    JP    Japan       377835          Tokyo   125960000     333.373033
    CN   China     9596960         Beijing  1439323688    149.977044
    RU   Russia   17100000       Moscow   146748600        8.581789

    데이터 분석

    기상청에서 2010년 ~ 2020년까지 울릉도의 기온, 최대풍속, 풍속의 데이터를 기록한 데이터를 다운로드하여오자.

    https://github.com/dongupak/DataSciPy/blob/master/data/csv/weather.csv

     

    이러한 데이터가 3000천 개가 넘게 있는데 맨 위의 6개 정도만 캡처 해왔다.

    waether.csv

    먼저 pandas로 읽어 들이자.

    한글이 들어있기 때문에 encoding='CP949'를 추가로 써주었다.

    >>> import pandas as pd
    >>> weather_df = pd.read_csv('../data/weather.csv', encoding='CP949', index_col=0)
    >>> weather_df
    
                평균기온  최대풍속  평균풍속
    일시                          
    2010-08-01  28.7   8.3   3.4
    2010-08-02  25.2   8.7   3.8
    2010-08-03  22.1   6.3   2.9
    2010-08-04  25.3   6.6   4.2
    2010-08-05  27.2   9.1   5.6
              ...   ...   ...
    2020-07-27  22.1   4.2   1.7
    2020-07-28  21.9   4.5   1.6
    2020-07-29  21.6   3.2   1.0
    2020-07-30  22.9   9.7   2.4
    2020-07-31  25.7   4.8   2.5
    
    [3653 rows x 3 columns]

     

    describe()

    전체적으로 데이터를 간단하게 분석하려면 describe() 함수를 사용하면 된다.

    데이터의 개수(count), 평균값(mean), 표준편차(std), 최솟값(min), 최댓값(max) 등을 알 수 있다.

    >>> weather_df.describe()
                  평균기온         최대풍속         평균풍속
    count  3653.000000  3649.000000  3647.000000
    mean     12.942102     7.911099     3.936441
    std       8.538507     3.029862     1.888473
    min      -9.000000     2.000000     0.200000
    25%       5.400000     5.700000     2.500000
    50%      13.800000     7.600000     3.600000
    75%      20.100000     9.700000     5.000000
    max      31.300000    26.000000    14.900000

     

    count(), mean(), std(), min(), max()를 사용하여 하나만을 분석할 수도 있다.

    >>> weather_df.max()
    평균기온    31.3
    최대풍속    26.0
    평균풍속    14.9
    dtype: float64

     

    사용 방법은 다 똑같다.  그러니 생략.

     

    10년간 데이터 중에 평균 풍속 중 가장 높은 값을 가져오려면 아래와 같이 한다.

    >>> weather_df['평균풍속'].max()
    14.9

    이러한 방식으로 다양하게 데이터를 분석할 수 있다.

     

    그룹핑

    데이터를 특정한 값에 기반하여 그룹으로 묶는 방법을 알아보자.

     

    아래의 데이터를 월별로 묶어 평균값을 내 보고 싶은데 천천히 살펴보자.

    >>> import pandas as pd
    >>> weather_df = pd.read_csv('../data/weather.csv', encoding='CP949')
    >>> weather_df
                  일시  평균기온  최대풍속  평균풍속
    0     2010-08-01  28.7   8.3   3.4
    1     2010-08-02  25.2   8.7   3.8
    2     2010-08-03  22.1   6.3   2.9
    3     2010-08-04  25.3   6.6   4.2
    4     2010-08-05  27.2   9.1   5.6
              ...   ...   ...   ...
    3648  2020-07-27  22.1   4.2   1.7
    3649  2020-07-28  21.9   4.5   1.6

     

    DatetimIndex

    먼저 날짜를 표시하는 방식으로 된 데이터를 DatetimeIndex 객체로 다룰 수 있다.

    DatetimeIndex에 대해 자세히 살펴보자

    >>> datetimeIndex = pd.DatetimeIndex(weather_df['일시'])
    >>> datetimeIndex
    DatetimeIndex(['2010-08-01', '2010-08-02', '2010-08-03', '2010-08-04',
                   '2010-08-05', '2010-08-06', '2010-08-07', '2010-08-08',
                   '2010-08-09', '2010-08-10',
                   ...
                   '2020-07-22', '2020-07-23', '2020-07-24', '2020-07-25',
                   '2020-07-26', '2020-07-27', '2020-07-28', '2020-07-29',
                   '2020-07-30', '2020-07-31'],
                  dtype='datetime64[ns]', name='일시', length=3653, freq=None)

     

    DatetimeIndex 객체에서 연도, 달, 일을 뽑아 올 수 있는데 방법은 아래와 같다.

    >>> datetimeIndex.year
    Int64Index([2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010,
                ...
                2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020],
               dtype='int64', name='일시', length=3653)
               
    >>> datetimeIndex.month
    Int64Index([8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
                ...
                7, 7, 7, 7, 7, 7, 7, 7, 7, 7],
               dtype='int64', name='일시', length=3653)
    
    >>> datetimeIndex.day
    Int64Index([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10,
                ...
                22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
               dtype='int64', name='일시', length=3653)

     

    이제 DatetimeIndex 객체를 활용하여 weather.csv를 분석해보자.

    weather.csv 월별로 묶기

    새로운 열 month를 생성하고 해당하는 달을 기록한다.

    new_df에 month가 같은 값끼리 묶어 평균을 내어 저장한다.

    import pandas as pd
    
    weather_df = pd.read_csv('../data/weather.csv', encoding='CP949')
    weather_df['month'] = pd.DatetimeIndex(weather_df['일시']).month
    new_df = weather_df.groupby('month').mean()
    
    print(new_df)
    
                평균기온      최대풍속      평균풍속
    month                               
    1       1.598387  8.158065  3.757419
    2       2.136396  8.225357  3.946786
    3       6.250323  8.871935  4.390291
    4      11.064667  9.305017  4.622483
    5      16.564194  8.548710  4.219355
    6      19.616667  6.945667  3.461000
    7      23.328387  7.322581  3.877419
    8      24.748710  6.853226  3.596129
    9      20.323667  6.896333  3.661667
    10     15.383871  7.766774  3.961613
    11      9.889667  8.013333  3.930667
    12      3.753548  8.045484  3.817097

     

    필터링

    weather.csv 에서 초속 10m/s 이상의 강풍이 불었던 날들을 찾아보고 싶을 때 아래와 같은 방법으로 할 수 있다.

    weather_df[weather_df['최대풍속'] >= 10.0]
                  일시  평균기온  최대풍속  평균풍속
    9     2010-08-10  25.6  10.2   5.5
    12    2010-08-13  24.3  10.9   4.6
    13    2010-08-14  25.0  10.8   4.4
    14    2010-08-15  24.5  16.9  10.3
    29    2010-08-30  26.2  10.5   6.2
              ...   ...   ...   ...
    3622  2020-07-01  16.8  19.7   8.7
    3632  2020-07-11  20.1  10.3   4.1
    3634  2020-07-13  17.8  10.3   4.6
    3635  2020-07-14  17.8  12.7   9.4
    3641  2020-07-20  23.0  11.2   7.3
    [830 rows x 4 columns]
    

    결측 데이터 처리

    결손 값

    데이터가 수집되지 않았거나 측정 장치의 고장, 사건 사고 등으로 데이터를 확보할 수 없을 수도 있다.

    그러한 값을 결손값이라한다.

     

    결손 값은isna() 함수를 이용하여 찾을 수 있다. 결손 값은 NaN으로 표기된다.

    weather_df[weather_df['평균풍속'].isna()]
                  일시  평균기온  최대풍속  평균풍속
    559   2012-02-11  -0.7   NaN   NaN
    560   2012-02-12   0.4   NaN   NaN
    561   2012-02-13   4.0   NaN   NaN
    1694  2015-03-22  10.1  11.6   NaN
    1704  2015-04-01   7.3  12.1   NaN
    3182  2019-04-18  15.7  11.7   NaN

     

    이러한 결손값은 fillna() 함수를 이용하여 채워줄 수 있다. 채울 값을 인자로 전달하고 inplace를 True로 설정하면 원본을 덮어쓴다는 뜻이다.

    결손 값을 채운 뒤 위에서 살펴봤던 559번째의 데이터를 출력해보니 0으로 채워진 것을 볼 수 있다.

    >>> weather_df.fillna(0, inplace=True)
    >>> weather_df.loc[559]
    일시      2012-02-11
    평균기온          -0.7
    최대풍속           0.0
    평균풍속           0.0
    Name: 559, dtype: object

    데이터 조작

    데이터 구조 변경

    import pandas as pd
    
    df_1 = pd.DataFrame({'item' : ['ring0', 'ring0', 'ring1', 'ring1'],
                         'type' : ['Gold', 'Silver', 'Gold', 'Bronze'],
                         'price': [20000, 10000, 50000, 30000]})
    
    df_2 = df_1.pivot(index='item', columns='type', values='price')
    
    print(df_1)
    print() # 단순 줄바꿈
    print(df_2)
        item    type  price
    0  ring0    Gold  20000
    1  ring0  Silver  10000
    2  ring1    Gold  50000
    3  ring1  Bronze  30000

    type    Bronze     Gold   Silver
    item                            
    ring0      NaN  20000.0  10000.0
    ring1  30000.0  50000.0      NaN

    df_1을 보면 동일한 상품이 서로 다른 행에 중복하여 두고 있어 자료를 찾기 쉽지 않다.

    인덱스를 item으로 하고 type을 열의 레이블로 하여 데이터 프레임을 변경하였다.

    pivot() 함수를 사용하였는데 index, columns, values를 각각 지정해주면 된다.

     

     

    데이터 프레임 합치기

    >>> import pandas as pd
    
    >>> df_1 = pd.DataFrame( {'A' : ['a10', 'a11', 'a12'],
                          'B' : ['b10', 'b11', 'b12'],
                          'C' : ['c10', 'c11', 'c12']} , index = ['가', '나',  '다'] )
    
    >>> df_2 = pd.DataFrame( {'B' : ['b23', 'b24', 'b25'],
                          'C' : ['c23', 'c24', 'c25'],
                          'D' : ['d23', 'd24', 'd25']} , index = ['다', '라',  '마'] )
    
    >>> df_1
         A    B    C
    가  a10  b10  c10
    나  a11  b11  c11
    다  a12  b12  c12
    >>> df_2
         B    C    D
    다  b23  c23  d23
    라  b24  c24  d24
    마  b25  c25  d25

    contcat()

    df_1과 df_2를 concat을 이용하여 합쳐보자.

    axis : 0이면 데이블의 행을 늘려서 붙여나감, 1이면 열을 늘려서 붙여 나감

    join : outer 이면 합집합, inner 이면 교집합으로 생성

     

    merge()

    데이터베이스는 Join 연산을 지원하는데 이 연산은 서로 다른 2개의 테이블을 결합하는 연산이다.

    이 join연산과 같은 방식의 데이터 병합을 지원하는 판다스 함수가 merge()이다.

    how : outer이면 합집합, inner이면 교집합,

    right 이면 outer 조인의 결과에서 왼쪽 프레임에 존재하는 키를 가진 것만 뽑아낸다.

    left 이면 outer 조인의 결과에서 오른쪽 프레임에 존재하는 키를 가진 것만 뽑아낸다.

    on : 조인 연산을 수행하기 위해 사용할 레이블

     

    데이터 정렬

    sort_values() 함수를 이용하여 쉽게 정렬할 수 있다. 인자로는 정렬시킬 열의 이름을 전달하면 된다.

    ascending=True : 오름차순

    ascending=False : 내림차순

    >>> import pandas as pd
    
    >>> countries_df = pd.read_csv('../data/countries.csv', index_col=0)
    >>> sorted = countries_df.sort_values('population', ascending=False)
    >>> sorted
       country      area     capital  population
    CN   China   9596960     Beijing  1439323688
    US     USA   9629091  Washington   331002825
    RU  Russia  17100000      Moscow   146748600
    JP   Japan    377835       Tokyo   125960000
    KR   Korea     98480       Seoul    51780579

    지금까지 배운 것들로

    울릉도의 바람 세기를 분석

    weather.csv의 데이터를 분석하여 월별 바람세기의 평균을 그래프로 나타내었다.

    import pandas as pd
    import matplotlib.pyplot as plt
    
    weather = pd.read_csv('../data/weather.csv', encoding='cp949')
    monthly = [None for x in range(12)]
    monthly_wind = [0 for y in range(12)]
    weather['month'] = pd.DatetimeIndex(weather['일시']).month
    
    for i in range(12):
        monthly[i] = weather[weather['month'] == i + 1]
        monthly_wind[i] = monthly[i]['평균풍속'].mean()
    
    
    plt.xlabel('months')
    plt.ylabel('wind speed')
    plt.plot(monthly_wind, 'red')
    plt.show()

     

    자동차 회사 연비 분석

    자동차 회사 P와 Q가 있다.

    P 회사의 차종별 마력, 총중량, 연비

      A B C D E F G
    마력 130 250 190 300 210 220 170
    총중량 1900 2600 2200 2900 2400 2300 2200
    연비 16.3 10.2 11.1 7.1 12.1 13.2 14.2

    Q 회사의 차종별 마력, 총중량, 연비

      A B C D
    마력 120 220 120 200
    총중량 1900 2100 1500 2900
    연비 18.3 19.2 21.1 17.3

    자동차 회사 P와 Q 중 어떤 회사의 차량이 평균적으로 연비가 높은지 분석해보자.

     

    import pandas as pd
    
    # 데이터 프레임 생성
    df_Q = pd.DataFrame({
        'name': ['A', 'B', 'C', 'D'],
        'horse power': [120, 220, 120, 200],
        'weight': [1.9, 2.1, 1.5, 2.9],
        'efficiency': [18.3, 19.2, 21.1, 17.3]
    })
    
    df_P = pd.DataFrame({
        'name': ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
        'horse power': [130, 250, 190, 300, 210, 220, 170],
        'weight': [1.9, 2.6, 2.2, 2.9, 2.4, 2.3, 2.2],
        'efficiency': [16.3, 10.2, 11.1, 7.1, 12.1, 13.2, 14.2]
    })
    
    # 인덱스를 name으로 만들고 df_P와 df_Q를 합침
    df_Q.set_index('name', inplace=True)
    df_P.set_index('name', inplace=True)
    df_concat = pd.concat([df_P, df_Q])
    
    # 각 차량의 제조사를 알 수 있게 'com' 열을 만듦
    df_P['com'] = 'P'
    df_Q['com'] = 'Q'
    df_concat = pd.concat([df_P, df_Q])
    print("------------DataFrame----------")
    print(df_concat)
    
    # 'com'열을 그루핑하여 회사별로 연비의 평균을 구함
    df_concat['hp x mile'] = (df_concat['horse power'] * df_concat['efficiency'])
    print("------------result----------")
    print(df_concat.groupby('com').mean()['hp x mile'])
    ------------DataFrame----------
          horse power  weight  efficiency com
    name                                     
    A             130     1.9        16.3   P
    B             250     2.6        10.2   P
    C             190     2.2        11.1   P
    D             300     2.9         7.1   P
    E             210     2.4        12.1   P
    F             220     2.3        13.2   P
    G             170     2.2        14.2   P
    A             120     1.9        18.3   Q
    B             220     2.1        19.2   Q
    C             120     1.5        21.1   Q
    D             200     2.9        17.3   Q
    ------------result----------
    com
    P    2395.285714
    Q    3103.000000
    Name: hp x mile, dtype: float64

    데이터 분석 너무너무 재밌는 것 같다.

    이번 장은 내용이 좀 많았는데 시간 가는 줄 모르고 블로그 작성했다. 

    728x90

    'Deep Learning > 인공지능 입문 코딩' 카테고리의 다른 글

    [CHAPTER 14] Machine Learning  (0) 2021.06.10
    [CHAPTER 13] OpenCV  (0) 2021.06.06
    [CHAPTER 11] 데이터 시각화 | matplotlib  (0) 2021.06.02
    [CHAPTER 10]넘파이(numpy)  (0) 2021.05.30
    [CHAPTER 9] 텍스트 처리  (0) 2021.05.29

    댓글

Designed by Tistory.