본문 바로가기
ML, DL/Data Analysis

[Pandas] Part 2. Groupby, Describe, Missing Value, String, Index

by Wordbe 2019. 10. 12.
728x90

9. Multiple filter criteria to DataFrame

C++ 에서 |는 비트연산자의 or을 의미하고, ||가 논리연산자의 or 을 의미하지만,

파이썬은 |가 논리연산자 or을 의미합니다. 또는 or이라고 적어도 됩니다.

and는 &, and로 표시합니다.

"상영시간이 200이상이거나 장르가 드라마인 영화목록"

movies[(movies.duration >= 200) | (movies.genre == 'Drama')]

select *

from movies

where movies.duration >= 200 or movies.genre == 'Drama'

movies[(movies.genre == 'Crime') | (movies.genre == 'Drama') | (movies.genre == 'Action')]

여러개의 or 조건이 있어서 이렇게 번거로운 상황이 발생할 때,

pandas는 쉬운 기능을 제공합니다.

movies[movies.genre.isin(['Crime', 'Drama', 'Action'])]

이 둘은 완전히 똑같습니다.

10. Questions, Describe()

1) csv파일을 불러올 수 있는 가장 빠른 방법

ufo = pd.read_csv('http://bit.ly/uforeports', nrow=3)

가장 위의 3개의 행만 불러옵니다.

전체를 불러오는 것은 아니지만, 대략적인 데이터의 구조를 파악할수 있습니다.

2) dataframe을 for문에서 이용하는 방법

for index, row in ufo.iterrows():
    print(index, row.City, row.State)

3) 데이터에서 non-numeric 타입 열만 제거하는 방법

drinks = pd.read_csv('http://bit.ly/drinksbycountry')
drinks.dtypes
>>
country                          object
beer_servings                     int64
spirit_servings                   int64
wine_servings                     int64
total_litres_of_pure_alcohol    float64
continent                        object
dtype: object
import numpy as np
drinks.select_dtypes(include=[np.number]).dtypes
>>
beer_servings                     int64
spirit_servings                   int64
wine_servings                     int64
total_litres_of_pure_alcohol    float64
dtype: object

4) .describe() 사용법

drinks.describe() # default는 numeric 타입의 모든 열을 반환한다.
drinks.describe(include='all') # 모든 열을 반환한다.
drinks.describe(include=['object', 'float']) # 특정 타입의 열을 반환한다.

11. Axis 사용법

drinks.mean(axis=1) # 의미있는(meaningful) 수치가 아니다.
drinks.mean(axis=0) # default는 axis=0

axis = 0 (default) : 각각의 column에 대해 모든 row에 대한 평균을 구합니다. (결과 column개)

axis = 1 : 각각의 row에 대해 모든 column에 대한 평균을 구합니다. (결과 row개)

12. String Method

orders['item_name'].str.upper()
orders[orders['item_name'].str.contains('Chicken')]

orders['choice_description'].str.replace('[', '').str.replace(']','')
orders['choice_description'].str.replace('[\[\]]','') # Regular expression

이 이외에도 slice() 등 스트링을 다루는 method 는 많습니다.

13. Series에서 Data type 변경

대표적으로 string으로 되어있는 숫자를 int나 float으로 바꾸고 싶을 때 쓰입니다.

drinks['beer_servings'] = drinks['beer_servings'].astype(float)

데이터 불러올 때부터 타입을 바꿀 수도 있습니다.

drinks = pd.read_csv('http://bit.ly/drinksbycountry', dtype={'beer_servings':float})
drinks.dtypes
orders['item_price'].str.replace('$', '').astype(float).mean()

"$2.99 " 에서 $를 없애고 float형으로 바꾼뒤, 평균을 구합니다.

orders['item_name'].str.contains('Chicken').astype(int).head()

"Chicken"을 포함하는 문자열이 있으면 True, 아니면 False로 나올 텐데,

이것들을 int형 즉, 1과 0으로 바꾸어주어 계산할 수 있게 도와줍니다.

14. Groupby

aggregation function으로 count, mean, max, min, sum 등이 있습니다.

예제

drinks.groupby('continent')['beer_servings'].mean()

>>
continent
Africa            61.471698
Asia              37.045455
Europe           193.777778
North America    145.434783
Oceania           89.687500
South America    175.083333
Name: beer_servings, dtype: float64

beer_servings 열에서 continent별로 평균을 구한 결과가 나옵니다.

SQL로 표현해 봅시다.

select continent, min(beer_servings)

from drinks

group by continent

위결과는 아래 코드에서 Africa를 바꾸어 Asia, ..., South America 까지 일일이 한작업을 한번에 보여줍니다.

drinks[drinks['continent'] == 'Africa']['beer_servings'].mean()

여러개의 aggregation function을 한꺼번에 써봅시다.

drinks.groupby('continent').beer_servings.agg(['count', 'min', 'max', 'sum'])

>>
    count    min    max    sum
continent                
Africa    53    0.0    376.0    3258.0
Asia    44    0.0    247.0    1630.0
Europe    45    0.0    361.0    8720.0
North America    23    1.0    285.0    3345.0
Oceania    16    0.0    306.0    1435.0
South America    12    93.0    333.0    2101.0

이번엔 표를 그래프로 바꾸어봅시다.

drinks.groupby('continent').mean()

>>
    beer_servings    spirit_servings    wine_servings    total_litres_of_pure_alcohol
continent                
Africa    61.471698    16.339623    16.264151    3.007547
Asia    37.045455    60.840909    9.068182    2.170455
Europe    193.777778    132.555556    142.222222    8.617778
North America    145.434783    165.739130    24.521739    5.995652
Oceania    89.687500    58.437500    35.625000    3.381250
South America    175.083333    114.750000    62.416667    6.308333
%matplotlib inline
drinks.groupby('continent').mean().plot(kind='bar')

15. Explore Pandas Series

movies.dtypes
>>
star_rating       float64
title              object
content_rating     object
genre              object
duration            int64
actors_list        object
dtype: object

movies 테이블의 각 열마다 데이터 타입을 확인해봅시다.

genre는 string값인데, object로 표시가 됩니다.

movies.genre.describe()
>>
count       979
unique       16
top       Drama
freq        278
Name: genre, dtype: object

object 타입은 count, unique, top, freq 정보를 알려주는군요.

duration 열은 int값입니다.

movies.duration.describe()
>>
count    979.000000
mean     120.979571
std       26.218010
min       64.000000
25%      102.000000
50%      117.000000
75%      134.000000
max      242.000000
Name: duration, dtype: float64

이에 대해서는 count, mean, std, min, ... 등 여러값을 보여주네요.

movies.genre.value_counts()
movies.genre.value_counts(normalize=True).head()
movies.genre.unique()
movies.genre.nunique()
%matplotlib inline
movies.genre.value_counts().plot(kind='bar')

movies.duration.mean()
movies.duration.value_counts()
movies.duration.plot(kind='hist')

다양한 값을 일일이 확인해 볼 수도있고,

matplotlib을 통해 bar나 histogram형식의 그래프도 출력해볼 수 있습니다.

각각의 genre(행)마다, content_rating(열)을 파악하고 싶다면, .crosstab()을 이용하면 됩니다.

pd.crosstab(movies.genre, movies.content_rating)

16. 결측값(Missing Value)

ufo.tail() # NaN은 결측값을 나타낸다.
>>

City    Colors Reported    Shape Reported    State    Time
18236    Grant Park    NaN    TRIANGLE    IL    12/31/2000 23:00
18237    Spirit Lake    NaN    DISK    IA    12/31/2000 23:00
18238    Eagle River    NaN    NaN    WI    12/31/2000 23:45
18239    Eagle River    RED    LIGHT    WI    12/31/2000 23:45
18240    Ybor    NaN    OVAL    FL    12/31/2000 23:59

ufo.isnull().tail()
ufo.notnull().tail()
ufo.isnull().sum() # 열마다 결측값 개수를 의미
ufo[ufo.City.isnull()] ## City열에서 NaN 포함된 행만 select

ufo.dropna(how='all').shape # 모든 열의 값이 NaN인 행을 삭제
ufo.dropna(how='any').shape # NaN이 하나라도 있는 행은 삭제
ufo.dropna(subset=['City', 'Shape Reported'], how='all').shape # 이 두열에서 모두 NaN이 있는 행을 삭제
ufo['Shape Reported'].fillna(value='VARIOUS', inplace=True) #Various 값을 모두 NaN으로 채운다.
ufo['Shape Reported'].value_counts(dropna=False) #dropna=True가 기본값이고, True면 NaN은 무시하고 count한다.

missing value를 이용해서, dropna로 해당 열이나 행을 제거할 수 있다.

17. Pandas Index (Part 1)

drinks.index # index는 모든 DataFrame의 속성으로 있고, 열에 포함되지 않는다.
drinks.columns
drinks.shape

# Index기능: Identification
drinks[drinks.continent=='South America']
drinks.loc[23, 'beer_servings'] # 인덱스를이용해서 해당 열, 행의 원소찾기

# Index를 다른 칼럼으로 바꾸기
drinks.set_index('country', inplace=True)
drinks.index
drinks.columns
drinks.shape

drinks.loc['Brazil', 'beer_servings']

# Index 이름 제거
drinks.index.name = None

# Index 이름 다시 생성 후, Index(숫자) 다시 생성
drinks.index.name = 'country'
drinks.reset_index(inplace=True)

.describe()를 이용한 인덱싱 응용방법을 봅시다.

drinks.describe()
>>
    beer_servings    spirit_servings    wine_servings total_litres_of_pure_alcohol
count    193.000000    193.000000    193.000000    193.000000
mean    106.160622    80.994819    49.450777    4.717098
std    101.143103    88.284312    79.697598    3.773298
min    0.000000    0.000000    0.000000    0.000000
25%    20.000000    4.000000    1.000000    1.300000
50%    76.000000    56.000000    8.000000    4.200000
75%    188.000000    128.000000    59.000000    7.200000
max    376.000000    438.000000    370.000000    14.400000

drinks.describe().index
>>
Index(['count', 'mean', 'std', 'min', '25%', '50%', '75%', 'max'], dtype='object')

drinks.describe().columns
>>
Index(['beer_servings', 'spirit_servings', 'wine_servings',
       'total_litres_of_pure_alcohol'],
      dtype='object')

drinks.describe().loc['25%', 'beer_servings']
20.0

18. Pandas Index (Part 2)

drinks.set_index('country', inplace=True)
drinks.continent.value_counts()
>>
Africa           53
Europe           45
Asia             44
North America    23
Oceania          16
South America    12
Name: continent, dtype: int64

drinks.continent.value_counts().values
>>
array([53, 45, 44, 23, 16, 12], dtype=int64)

drinks.continent.value_counts().sort_values() # Descending order
drinks.continent.value_counts().sort_index() # Ascending order

해당하는 row index에 짝이 있으면, 연산을 하고, 아니면 NaN을 반환합니다.

people = pd.Series([3000000, 85000], index=['Albania', 'Andorra'], name='population')
drinks.beer_servings * people
>>
Afghanistan            NaN
Albania        267000000.0
Algeria                NaN
Andorra         20825000.0
Angola                 NaN
                  ...     
Venezuela              NaN
Vietnam                NaN
Yemen                  NaN
Zambia                 NaN
Zimbabwe               NaN
Length: 193, dtype: float64

.concat() 아래와 같이 하면 right outer join과 비슷한 것 같습니다.

pd.concat([drinks, people], axis=1).head()
>>
    beer_servings    spirit_servings    wine_servings    total_litres_of_pure_alcohol    continent    population
Afghanistan    0.0    0    0    0.0    Asia    NaN
Albania    89.0    132    54    4.9    Europe    3000000.0
Algeria    25.0    0    14    0.7    Africa    NaN
Andorra    245.0    138    312    12.4    Europe    85000.0
Angola    217.0    57    45    5.9    Africa    NaN

population 열이 원래 테이블 오른쪽에 생기고, 알맞은 짝의 row index에만 값이 들어가있습니다.

19. Select multiple rows and columns

1) loc

ufo.loc[0, :] # 0번 row를 뽑아서 Series로 만들어줌
ufo.loc[0:2, :] # 0, 1, 2번 row를 뽑아서 dataframe로 만들어줌
ufo.loc[0:2] # 비추: 파이썬 코드는 명시적(Explicit)인 것이 좋아서 :를 쓰자.
ufo.loc[0:2, 'City':'State']

ufo.head(3).drop('Time', axis=1) # 이렇게 하는 것보다 loc을 사용하는 것이 작성력, 가독성에 더 도움이됨

ufo[ufo.City=='Oakland']
ufo.loc[ufo.City=='Oakland', :] # 이것이 조금 더 explict하다. 조금 더 safe하다

2) iloc

ufo.iloc[:, 0:4] # index를 통해 접근
ufo.iloc[0:3, :] # loc은 0:3하면 3까지 포함하지만, iloc은 3은 배제한다.

ufo[['City', 'State']]
ufo.loc[:, ['City', 'State']] # 위에 보다 이렇게 쓰는 것을 권장(Explicit)

ufo[0:2]
ufo.iloc[0:2, :] # 위에 보다 이렇게 쓰는 것을 권장(Explicit)

3) ix (will be deprecated) position(숫자), label(이름, 스트링)을 병행해서 사용

drinks = pd.read_csv('http://bit.ly/drinksbycountry', index_col='country')
>>
beer_servings    spirit_servings    wine_servings    total_litres_of_pure_alcohol    continent
country                    
Afghanistan    0    0    0    0.0    Asia
Albania    89    132    54    4.9    Europe
Algeria    25    0    14    0.7    Africa
Andorra    245    138    312    12.4    Europe
Angola    217    57    45    5.9    Africa


drinks.ix['Albania', 0]
drinks.ix[1, 'beer_servings']

drinks.ix['Albania':'Andorra', 0:2]
ufo.ix[0:2, 0:2] # position(0, 1, 2 다나옴)과 label(2는 배제)을 동시에 사용할 때만 사용권장, 아니면 헷갈림, 그리고 ix는 deprecated될것임.

20. Inplace Parameter

inplace=False 디폴트값인 이유는, 기존 데이터를 덮어씌우는 작업이기 때문에,

False상태로 여러 번 시도해 본 후,

하는 작업을 확정짓고 True를 적어주어서 덮어씌우는 작업을 합니다.

ufo.set_index('Time', inplace=True)
# ufo = ufo.set_index('Time') # 복사되고 할당하므로 비효율적.

inplace=True를 설정하기 전에는 잘 모르는 method도 여러번 실험해 볼 수 있다는 데에 장점이 있습니다.

ufo.fillna(method='bfill').head()
ufo.fillna(method='ffill').head()

[참고 - Data School https://www.youtube.com/watch?v=-NbY7E9hKxk&list=PL5-da3qGB5ICCsgW1MxlZ0Hq8LL5U3u9y&index=32]

728x90

댓글