7 분 소요

import warnings
warnings.filterwarnings('ignore')
from IPython.display import Image
import numpy as np
import pandas as pd
import seaborn as sns
df = pd.read_csv('./data/gapminder.tsv', sep='\t')
df.head()
country continent year lifeExp pop gdpPercap
0 Afghanistan Asia 1952 28.801 8425333 779.445314
1 Afghanistan Asia 1957 30.332 9240934 820.853030
2 Afghanistan Asia 1962 31.997 10267083 853.100710
3 Afghanistan Asia 1967 34.020 11537966 836.197138
4 Afghanistan Asia 1972 36.088 13079460 739.981106
#groupby()함수를 이용해서 특정 열을 기준으로 데이터를
#그룹화 할 수 있다.
age_lifeExp_by_year = df.groupby('year').lifeExp.mean()
age_lifeExp_by_year

# groupby() 함수와 같이 사용하는 집계 함수
# count() => 누락값을 제외한 데이터 개수
# size() => 누락값을 포함한 데이터 개수
# mean() => 평균
# std() => 표준편차
# min() => 최소값
# quantile(q = 0.25) => 1사분위수
# quantile(q = 0.50) => 중위수
# quantile(q = 0.75) => 3사분위수
# max() => 최대값
# sum() => 합계
# var() => 분산
# sem() => 평균의 표준편차
# describe() => 데이터 개수, 평균, 표준편차, 최소값, 사분위수, 최대값을 모두 반환
# first() => 첫 번째 행 반환
# last() => 마지막 행 반환
# nth() => n번재 행 반환
year
1952    49.057620
1957    51.507401
1962    53.609249
1967    55.678290
1972    57.647386
1977    59.570157
1982    61.533197
1987    63.212613
1992    64.160338
1997    65.014676
2002    65.694923
2007    67.007423
Name: lifeExp, dtype: float64
#agg() 함수를 사용하면 사용자 정의 함수를 groupby()함수로 
#그룹화한 데이터에 일괄적으로 적용할 수 있다. 

#agg()함수로 사용자 정의 함수와 groupby함수 조합하기.
#평균
def my_mean(values):
    sum = 0
    for i in values:
        sum +=i
    return (sum/len(values))

my_mean([1,2,3,4,5])

#판다스가 제공하는 집계함수는 groupby()함수로 그룹화한 결과가
#자동으로 전달되서 실행되지만 사용자 정의 함수에는 그렇게 안된다.
#agg() 함수의 인수로 실행할 사용자 정의 함수의 이름을 넘겨준다.
#=>이때 함수의 이름만 써야하고 ()는 입력하지 않는다.

#agg의 함수의 첫 번째 인수로 그룹화된 데이터가 자동으로 넘어간다.
age_my_mean = df.groupby('year').lifeExp.agg(my_mean)
age_my_mean
year
1952    49.057620
1957    51.507401
1962    53.609249
1967    55.678290
1972    57.647386
1977    59.570157
1982    61.533197
1987    63.212613
1992    64.160338
1997    65.014676
2002    65.694923
2007    67.007423
Name: lifeExp, dtype: float64
#year 별로 계산된 그룹 평균과 전체 평균의
#편차를 계산한다.
def my_mean_diff(values, diff_value):
    n = len(values)
    total = 0
    for value in values:
        total += value
    mean = total / n
    
    #그룹별 평균(mean)에서 전체 평균을 뺀
    #값을 리턴시킨다
    return mean - diff_value
#전체 평균을 계산한다.
global_mean = df.lifeExp.mean()
print(global_mean)
59.474439366197174
#그룹화된 첫번재 정보가 my_mean_diff의 첫번재 인수(values)로 전달되고
#diff_value란 두번째 인수엔 global_mean의 값을 넣어준다.
age_mean_diff = df.groupby('year').lifeExp.agg(my_mean_diff, diff_value=global_mean)
age_mean_diff
year
1952   -10.416820
1957    -7.967038
1962    -5.865190
1967    -3.796150
1972    -1.827053
1977     0.095718
1982     2.058758
1987     3.738173
1992     4.685899
1997     5.540237
2002     6.220483
2007     7.532983
Name: lifeExp, dtype: float64
#한개의 열에 대해서 여러개의 함수를 실행한다.
#그룹화한 한개의 열에 집계 함수를 2개 이상 
#실행하려는 경우 agg()함수에 집계 함수를
#리스트에 담아서 전달한다.
#(이때 함수와 함께 ()를 넣지는 않는다.)
gdf = df.groupby('year').lifeExp.agg([np.count_nonzero, np.mean, np.std])
gdf
count_nonzero mean std
year
1952 142.0 49.057620 12.225956
1957 142.0 51.507401 12.231286
1962 142.0 53.609249 12.097245
1967 142.0 55.678290 11.718858
1972 142.0 57.647386 11.381953
1977 142.0 59.570157 11.227229
1982 142.0 61.533197 10.770618
1987 142.0 63.212613 10.556285
1992 142.0 64.160338 11.227380
1997 142.0 65.014676 11.559439
2002 142.0 65.694923 12.279823
2007 142.0 67.007423 12.073021
#여러개의 열에 대해서 여러개의 함수를 실행한다.
#그릅화한 2개 이상의 열에 집계 함수를 2개 이상 
#사용하려는 경우 딕셔너리에 계산할 열과
#사용할 함수를 key와 value로 묶어서 전달하면
#된다.
gdf = df.groupby('year').agg({'lifeExp' : 'mean', 'pop' : 'median',
                             'gdpPercap' : 'max'})
gdf
lifeExp pop gdpPercap
year
1952 49.057620 3943953.0 108382.35290
1957 51.507401 4282942.0 113523.13290
1962 53.609249 4686039.5 95458.11176
1967 55.678290 5170175.5 80894.88326
1972 57.647386 5877996.5 109347.86700
1977 59.570157 6404036.5 59265.47714
1982 61.533197 7007320.0 33693.17525
1987 63.212613 7774861.5 31540.97480
1992 64.160338 8688686.5 34932.91959
1997 65.014676 9735063.5 41283.16433
2002 65.694923 10372918.5 44683.97525
2007 67.007423 10517531.0 49357.19017
#표준점수 계산하기
#데이터의 평균과 표준편차의 차이를
#표준점수라 부른다.
#표준점수를 구하면 변환된 데이터의 
#평균이 0이 되고 표준편차는 1이 
#된다. 그러면 데이터가 표준화되어
#서로 다른 데이터를 쉽게 비교할 수
#있다.
def my_zscore(x):
    return(x-x.mean()) / x.std()
#agg() 함수는 그룹별 대표값을 만드는 함수이므로
#agg()함수로 실행하는 함수(my_zscore)에서는
#브로드캐스팅(x-x.mean())이 실행되면 안된다.
#dfz = df.groupby('year').lifeExp.agg(my_zscore)
#=>에러 발생

#브로드캐스팅을 실행해야 하는 함수를 실행해야
#한다면 transform()함수를 사용한다.
df['zscore'] = df.groupby('year').lifeExp.transform(my_zscore)
df
country continent year lifeExp pop gdpPercap zscore
0 Afghanistan Asia 1952 28.801 8425333 779.445314 -1.656854
1 Afghanistan Asia 1957 30.332 9240934 820.853030 -1.731249
2 Afghanistan Asia 1962 31.997 10267083 853.100710 -1.786543
3 Afghanistan Asia 1967 34.020 11537966 836.197138 -1.848157
4 Afghanistan Asia 1972 36.088 13079460 739.981106 -1.894173
... ... ... ... ... ... ... ...
1699 Zimbabwe Africa 1987 62.351 9216418 706.157306 -0.081621
1700 Zimbabwe Africa 1992 60.377 10704340 693.420786 -0.336974
1701 Zimbabwe Africa 1997 46.809 11404948 792.449960 -1.574962
1702 Zimbabwe Africa 2002 39.989 11926563 672.038623 -2.093346
1703 Zimbabwe Africa 2007 43.487 12311143 469.709298 -1.948180

1704 rows × 7 columns

누락값을 평균값으로 처리하기

# seaborn 라이브러리의 tips데이터 집합에서
# 10개의 행 데이터만 가져온 다음
# total_bill열의 값4개를 임의로 선택해서
# 누락값으로 바꾼다.
np.random.seed(42)

# sample()함수는 인수로 지정된 개수만큼
# 전체 데이터에서 랜덤하게 데이터를 추출한다.
# import seaborn as sns 참조한다.
tips_10 = sns.load_dataset('tips').sample(10)
tips_10 
total_bill tip sex smoker day time size
24 19.82 3.18 Male No Sat Dinner 2
6 8.77 2.00 Male No Sun Dinner 2
153 24.55 2.00 Male No Sun Dinner 4
211 25.89 5.16 Male Yes Sat Dinner 4
198 13.00 2.00 Female Yes Thur Lunch 2
176 17.89 2.00 Male Yes Sun Dinner 2
192 28.44 2.56 Male Yes Thur Lunch 2
124 12.48 2.52 Female No Thur Lunch 2
9 14.78 3.23 Male No Sun Dinner 2
101 15.38 3.00 Female Yes Fri Dinner 2
#넘파이에서 permutation(), shuffle()함수는 무작위로 배열을 섞는다.
#차이점
#1. permutation() => 배열을 복사해서 리턴하기에 원본이 유지된다.
#2. shuffle()     => 원본 자체를 수정한다.
x = np.arange(10)
print(x) #[0 1 2 3 4 5 6 7 8 9]이 출력된다. =>원본

#permutation == 순열
#섞인 결과가 출력된다.
print(np.random.permutation(x))
print(x) #[0 1 2 3 4 5 6 7 8 9]이 출력된다. => permutation()함수는 원본을 변형시키지 않는다.
print(np.random.shuffle(x)) #None이 출력된다. => 섞여서 리턴되는 값이 없다. =>원본 자체를 섞어버린다.
print(x) #원본 데이터가 섞여서 출력된다.
[0 1 2 3 4 5 6 7 8 9]
[5 3 4 2 9 1 6 7 0 8]
[0 1 2 3 4 5 6 7 8 9]
None
[0 3 7 4 2 9 5 8 6 1]
tips_10.loc[np.random.permutation(tips_10.index)[:4], 'total_bill'] = np.NaN
tips_10
total_bill tip sex smoker day time size
24 19.82 3.18 Male No Sat Dinner 2
6 8.77 2.00 Male No Sun Dinner 2
153 NaN 2.00 Male No Sun Dinner 4
211 25.89 5.16 Male Yes Sat Dinner 4
198 NaN 2.00 Female Yes Thur Lunch 2
176 NaN 2.00 Male Yes Sun Dinner 2
192 28.44 2.56 Male Yes Thur Lunch 2
124 NaN 2.52 Female No Thur Lunch 2
9 14.78 3.23 Male No Sun Dinner 2
101 15.38 3.00 Female Yes Fri Dinner 2
#total_bill열의 누락값을 단순히 total_bill열의 전체
#평균으로 채우면 안된다.
#현재 tips_10의 데이터는 여성보다 남성이 많기 때문에
#여성과 넘성을 구분해서 total_bill열의 평균값을
#계산하지 않으면 여성 데이터가 남성 데이터의 영향(간섭)을
#받아서 여성 데이터가 훼손될 수 있다.
#성별로 그룹화 해 보면 남성의 누락값은 3개 여성의 누락값은
#한개인 것을 확인할 수 있다.
count_sex = tips_10.groupby('sex').count()
count_sex
total_bill tip smoker day time size
sex
Male 5 7 7 7 7 7
Female 1 3 3 3 3 3
#성별을 구분해서 total_bill열의 데이터를 받아
#평균을 계산하는 함수
def fill_na_mean(x):
    avg = x.mean()
    return x.fillna(avg)
total_bill_group_mean = tips_10.groupby('sex').total_bill.transform(fill_na_mean)
total_bill_group_mean
24     19.82
6       8.77
153    19.54
211    25.89
198    15.38
176    19.54
192    28.44
124    15.38
9      14.78
101    15.38
Name: total_bill, dtype: float64
tips_10.total_bill.mean()
18.846666666666668
tips_10.groupby('sex').total_bill.mean()
sex
Male      19.54
Female    15.38
Name: total_bill, dtype: float64

누락값을 남,여 구분없에 전체 평균으로 체운다.

np.random.seed(42)
tips_10 = sns.load_dataset('tips').sample(10)
tips_10.loc[np.random.permutation(tips_10.index)[:4], 'total_bill'] = np.NaN
tips_10
total_bill tip sex smoker day time size
24 19.82 3.18 Male No Sat Dinner 2
6 8.77 2.00 Male No Sun Dinner 2
153 NaN 2.00 Male No Sun Dinner 4
211 NaN 5.16 Male Yes Sat Dinner 4
198 NaN 2.00 Female Yes Thur Lunch 2
176 NaN 2.00 Male Yes Sun Dinner 2
192 28.44 2.56 Male Yes Thur Lunch 2
124 12.48 2.52 Female No Thur Lunch 2
9 14.78 3.23 Male No Sun Dinner 2
101 15.38 3.00 Female Yes Fri Dinner 2
tips_10['total_bill'] = tips_10.total_bill.fillna(tips_10.total_bill.mean())
tips_10   
total_bill tip sex smoker day time size
24 19.820000 3.18 Male No Sat Dinner 2
6 8.770000 2.00 Male No Sun Dinner 2
153 16.611667 2.00 Male No Sun Dinner 4
211 16.611667 5.16 Male Yes Sat Dinner 4
198 16.611667 2.00 Female Yes Thur Lunch 2
176 16.611667 2.00 Male Yes Sun Dinner 2
192 28.440000 2.56 Male Yes Thur Lunch 2
124 12.480000 2.52 Female No Thur Lunch 2
9 14.780000 3.23 Male No Sun Dinner 2
101 15.380000 3.00 Female Yes Fri Dinner 2

댓글남기기