320x100
# Pandas GroupBy Operations
## Understanding GroupBy objects
import pandas as pd
titanic = pd.read_csv('titanic.csv')
titanic.head()
'''
survived pclass sex age sibsp parch fare embarked deck
0 0 3 male 22.0 1 0 7.2500 S NaN
1 1 1 female 38.0 1 0 71.2833 C C
2 1 3 female 26.0 0 0 7.9250 S NaN
3 1 1 female 35.0 1 0 53.1000 S C
4 0 3 male 35.0 0 0 8.0500 S NaN
'''
titanic.info()
'''
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 survived 891 non-null int64
1 pclass 891 non-null int64
2 sex 891 non-null object
3 age 714 non-null float64
4 sibsp 891 non-null int64
5 parch 891 non-null int64
6 fare 891 non-null float64
7 embarked 889 non-null object
8 deck 203 non-null object
dtypes: float64(2), int64(4), object(3)
memory usage: 62.8+ KB
'''
# titanic 변수에 대해서
# 행 rows를 처음부터 9번까지 슬라이스 해줘라
# 열 columns를 2,3번에 대해서 출력해줘라.
titanic.iloc[:10, [2,3]]
'''
sex age
0 male 22.0
1 female 38.0
2 female 26.0
3 female 35.0
4 male 35.0
5 male NaN
6 male 54.0
7 male 2.0
8 female 27.0
9 female 14.0
'''
titanic_slice = titanic.iloc[:10, [2,3]]
titanic_slice.groupby('sex')
# <pandas.core.groupby.generic.DataFrameGroupBy object at 0x7f80c262cd60>
gbo = titanic_slice.groupby('sex')
type(gbo)
# pandas.core.groupby.generic.DataFrameGroupBy
# sex를 기준으로 그룹화 된 것들이 각각 인덱스 번호가 어떻게 되는지 표현해주는 메소드
gbo.groups
# {'female': [1, 2, 3, 8, 9], 'male': [0, 4, 5, 6, 7]}
l = list(gbo)
'''
[('female',
sex age
1 female 38.0
2 female 26.0
3 female 35.0
8 female 27.0
9 female 14.0),
('male',
sex age
0 male 22.0
4 male 35.0
5 male NaN
6 male 54.0
7 male 2.0)]
'''
len(l)
# 2
l[0]
'''
('female',
sex age
1 female 38.0
2 female 26.0
3 female 35.0
8 female 27.0
9 female 14.0)
'''
l[1]
'''
('male',
sex age
0 male 22.0
4 male 35.0
5 male NaN
6 male 54.0
7 male 2.0)
'''
titanic_slice.loc[titanic_slice.sex == 'female']
'''
sex age
1 female 38.0
2 female 26.0
3 female 35.0
8 female 27.0
9 female 14.0
'''
titanic.loc[titanic.sex == 'female'].reset_index()
titanic_slice_f = titanic_slice.loc[titanic_slice.sex == 'female']
titanic_slice_f.equals(l[0][1])
# True
for element in gbo:
print(element[1])
## Splitting with many Keys
import pandas as pd
summer = pd.read_csv('summer.csv')
summer.head()
'''
Year City Sport Discipline Athlete Country Gender Event Medal
0 1896 Athens Aquatics Swimming HAJOS, Alfred HUN Men 100M Freestyle Gold
1 1896 Athens Aquatics Swimming HERSCHMANN, Otto AUT Men 100M Freestyle Silver
2 1896 Athens Aquatics Swimming DRIVAS, Dimitrios GRE Men 100M Freestyle For Sailors Bronze
3 1896 Athens Aquatics Swimming MALOKINIS, Ioannis GRE Men 100M Freestyle For Sailors Gold
4 1896 Athens Aquatics Swimming CHASAPIS, Spiridon GRE Men 100M Freestyle For Sailors Silver
'''
summer.Country.nunique()
# 147
# nunique 정확히 무슨뜻이였더라?
# summer는 기본적으로 31165개의 행으로 이루어져있는 변수다.
# 그 중에서 Country 컬럼에 귀속된 수 많은 값 중에서
# 중복없이 고유한 값인 경우의 수가 147이라는 말 같다.
summer.info()
'''
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 31165 entries, 0 to 31164
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Year 31165 non-null int64
1 City 31165 non-null object
2 Sport 31165 non-null object
3 Discipline 31165 non-null object
4 Athlete 31165 non-null object
5 Country 31161 non-null object
6 Gender 31165 non-null object
7 Event 31165 non-null object
8 Medal 31165 non-null object
dtypes: int64(1), object(8)
memory usage: 2.1+ MB
'''
split1 = summer.groupby('Country')
l = list(split1)
len(l)
# 147
# 국가명
l[1][0]
# 'AHO'
# 해당 국가에 귀속된 리스트
# 첫번째 리스트에 들어갈 숫자는 그 순서의 국가를 의미하고
# 두번째 리스트에 들어갈 숫자로는 0은 국가명
# 1은 해당 국가에 귀속된 인원들의 정보를 의미한다.
l[1][1]
'''
Year City Sport Discipline Athlete Country Gender Event Medal
19323 1988 Seoul Sailing Sailing BOERSMA, Jan D. AHO Men Board (Division Ii) Silver
'''
# 2개의 컬럼으로 그룹이라..
split2 = summer.groupby(by = ['Country', 'Gender'])
l2 = list(split2)
len(l2)
# 236
# 원리는 같다.
# 첫번째 리스트에 들어간 100은 100번 행 인덱스의 순서를 의미하고
# 두번째 리스트에 들어간 0은 groupby로 잡아준 Country 컬럼의 이름과 Gender 컬럼의 이름이 출력 된다.
l2[100][0]
# 두번째 컬럼 값이 1이면 귀속된 값이 나오고.
l2[100][1]
'''
Year City Sport Discipline Athlete Country Gender Event Medal
21081 1992 Barcelona Shooting Shooting PLETIKOSIC, Stevan IOP Men 50M Rifle Prone (60 Shots) Bronze
'''
## split-apply-combine explained
import pandas as pd
titanic = pd.read_csv('titanic.csv')
titanic_slice = titanic.iloc[:10, [2,3]]
list(titanic_slice.groupby('sex'))[0][1]
'''
sex age
1 female 38.0
2 female 26.0
3 female 35.0
8 female 27.0
9 female 14.0
'''
list(titanic_slice.groupby('sex'))[1][1]
'''
sex age
0 male 22.0
4 male 35.0
5 male NaN
6 male 54.0
7 male 2.0
'''
titanic.groupby('sex').sum()
'''
survived pclass age sibsp parch fare
sex
female 233 678 7286.00 218 204 13966.6628
male 109 1379 13919.17 248 136 14727.2865
'''
# 위의 체인 메서드? 와 관련하여 한번 더 나아가자면 이렇게도 사용이 가능하다.
titanic.groupby('sex').survived.sum()
'''
sex
female 233
male 109
Name: survived, dtype: int64
'''
titanic.groupby('sex')[['fare', 'age']].max()
'''
fare age
sex
female 512.3292 63.0
male 512.3292 80.0
'''
new_df = titanic.groupby('sex').mean()
'''
survived pclass age sibsp parch fare
sex
female 0.742038 2.159236 27.915709 0.694268 0.649682 44.479818
male 0.188908 2.389948 30.726645 0.429809 0.235702 25.523893
'''
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('seaborn')
# subplots를 True로 했다는건, 각 그래프에 대해서 제목을 표시해주겠다. 라는 뜻이다.
new_df.plot(kind = 'bar', subplots = True, figsize = (8,15), fontsize = 13)
plt.show()
## split-apply-combine applied
import pandas as pd
summer = pd.read_csv('summer.csv')
# 종류에 상관없이 Country 기준으로 분류한 후에 Medal의 갯수를 세어주기
summer.groupby('Country').Medal.count()
'''
Country
AFG 2
AHO 1
ALG 15
ANZ 29
ARG 259
...
VIE 2
YUG 435
ZAM 2
ZIM 23
ZZX 48
Name: Medal, Length: 147, dtype: int64
'''
medals_per_country = summer.groupby('Country').Medal.count()
medals_per_country
'''
Country
AFG 2
AHO 1
ALG 15
ANZ 29
ARG 259
...
VIE 2
YUG 435
ZAM 2
ZIM 23
ZZX 48
Name: Medal, Length: 147, dtype: int64
'''
# 가장 큰 순서대로 20개 나열 하는 방법
# rank와 같은 기능
medals_per_country = summer.groupby('Country').Medal.count().nlargest(n = 20)
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('seaborn')
medals_per_country.plot(kind = 'bar', figsize = (14,8), fontsize = 14, rot = 45)
plt.xlabel('Country', fontsize = 13)
plt.ylabel('No. of Medals', fontsize = 13)
plt.title('Summer Olympic Games (Total Medals per Country)', fontsize = 16)
plt.show()
titanic = pd.read_csv('titanic.csv')
titanic.describe()
'''
survived pclass age sibsp parch fare
count 891.000000 891.000000 714.000000 891.000000 891.000000 891.000000
mean 0.383838 2.308642 29.699118 0.523008 0.381594 32.204208
std 0.486592 0.836071 14.526497 1.102743 0.806057 49.693429
min 0.000000 1.000000 0.420000 0.000000 0.000000 0.000000
25% 0.000000 2.000000 20.125000 0.000000 0.000000 7.910400
50% 0.000000 3.000000 28.000000 0.000000 0.000000 14.454200
75% 1.000000 3.000000 38.000000 1.000000 0.000000 31.000000
max 1.000000 3.000000 80.000000 8.000000 6.000000 512.329200
'''
# titanic의 운임료 평균
titanic.fare.mean()
# 32.2042079685746
# pclass 그룹별로 분할해서 정리한 후에
# 운임료의 평균
titanic.groupby('pclass').fare.mean()
'''
pclass
1 84.154687
2 20.662183
3 13.675550
Name: fare, dtype: float64
'''
# 생존자 수
titanic.survived.sum()
# 342
# 왜 이게 가능하냐면, 사망자는 0, 생존자는 1이기 때문이다.
titanic.groupby('sex').survived.mean()
'''
sex
female 0.742038
male 0.188908
Name: survived, dtype: float64
'''
# 생존률
titanic.groupby('pclass').survived.mean()
'''
pclass
1 0.629630
2 0.472826
3 0.242363
Name: survived, dtype: float64
'''
# 나이에 따른 아이를 구별하기 위한 수식이다.
# 왜냐하면 따로 구별이 없기 때문이다.
titanic['ad_chi'] = 'adult'
# 나이가 18 미만일 경우, ad_chi의 필드값을 child로 오버라이드 해준다.
titanic.loc[titanic.age < 18, 'ad_chi'] = 'child'
titanic.head()
'''
survived pclass sex age sibsp parch fare embarked deck ad_chi
0 0 3 male 22.0 1 0 7.2500 S NaN adult
1 1 1 female 38.0 1 0 71.2833 C C adult
2 1 3 female 26.0 0 0 7.9250 S NaN adult
3 1 1 female 35.0 1 0 53.1000 S C adult
4 0 3 male 35.0 0 0 8.0500 S NaN adult
'''
titanic.ad_chi.value_counts()
'''
adult 778
child 113
Name: ad_chi, dtype: int64
'''
# mean의 정확한 개념은, '구성비율'인것 같다.
titanic.groupby('ad_chi').survived.mean()
'''
ad_chi
adult 0.361183
child 0.539823
Name: survived, dtype: float64
'''
titanic.groupby(['sex', 'ad_chi']).survived.count()
'''
sex ad_chi
female adult 259
child 55
male adult 519
child 58
Name: survived, dtype: int64
'''
titanic.groupby(['sex', 'ad_chi']).survived.mean().sort_values(ascending = False)
'''
sex ad_chi
female adult 0.752896
child 0.690909
male child 0.396552
adult 0.165703
Name: survived, dtype: float64
'''
w_and_c_first = titanic.groupby(['sex', 'ad_chi']).survived.mean().sort_values(ascending = False)
w_and_c_first.plot(kind = 'bar', figsize = (14,8), fontsize = 14, rot = 360)
plt.xlabel('Groups', fontsize = 13)
plt.ylabel('Survival Rate', fontsize = 13)
plt.title('Titanic Survival Rate by Sex/Age-Groups', fontsize = 16)
plt.show()
titanic.groupby('sex')[['survived', 'pclass', 'age', 'fare']].agg(['sum', 'mean'])
'''
survived pclass age fare
sum mean sum mean sum mean sum mean
sex
female 233 0.742038 678 2.159236 7286.00 27.915709 13966.6628 44.479818
male 109 0.188908 1379 2.389948 13919.17 30.726645 14727.2865 25.523893
'''
## Advanced Aggregation with agg()
import pandas as pd
titanic = pd.read_csv('titanic.csv', usecols = ['survived', 'pclass', 'sex', 'age', 'fare'])
titanic.head()
'''
survived pclass sex age fare
0 0 3 male 22.0 7.2500
1 1 1 female 38.0 71.2833
2 1 3 female 26.0 7.9250
3 1 1 female 35.0 53.1000
4 0 3 male 35.0 8.0500
'''
# titanic.groupby('sex')
# 단순히 groupby 만 해주면
# <pandas.core.groupby.generic.DataFrameGroupBy object at 0x7fab88bc0dc0>
# 이렇게 출력 된다.
# 따라서, 활용을 위해서는 변수지정을 해서 변수로 활용해주거나,
titanic.groupby('sex').mean()
'''
survived pclass age fare
sex
female 0.742038 2.159236 27.915709 44.479818
male 0.188908 2.389948 30.726645 25.523893
'''
# 이렇게 활용해 준다.
titanic.groupby('sex').sum()
'''
survived pclass age fare
sex
female 233 678 7286.00 13966.6628
male 109 1379 13919.17 14727.2865
'''
# groupby 다중 선택
titanic.groupby('sex').agg(['mean', 'sum', 'min', 'max'])
'''
survived pclass age fare
mean sum min max mean sum min max mean sum min max mean sum min max
sex
female 0.742038 233 0 1 2.159236 678 1 3 27.915709 7286.00 0.75 63.0 44.479818 13966.6628 6.75 512.3292
male 0.188908 109 0 1 2.389948 1379 1 3 30.726645 13919.17 0.42 80.0 25.523893 14727.2865 0.00 512.3292
'''
# 특정 컬럼을
# 딕셔너리 처리해서
# 다중 조건으로 groupby 해주기
titanic.groupby('sex').agg({'survived': ['sum', 'mean'], 'pclass': 'mean', 'age':['mean', 'median'], 'fare':'max'})
## Groupby Aggregation with Relabeling (new in Version 0.25)
import pandas as pd
titanic = pd.read_csv('titanic.csv', usecols = ['survived', 'pclass', 'sex', 'age', 'fare'])
titanic.head()
'''
survived pclass sex age fare
0 0 3 male 22.0 7.2500
1 1 1 female 38.0 71.2833
2 1 3 female 26.0 7.9250
3 1 1 female 35.0 53.1000
4 0 3 male 35.0 8.0500
'''
titanic.groupby('sex').survived.mean()
'''
sex
female 0.742038
male 0.188908
Name: survived, dtype: float64
'''
titanic.groupby('sex').agg(survival_rate = ('survived', 'mean'))
'''
survival_rate
sex
female 0.742038
male 0.188908
'''
# 이 부분이 흥미롭다.
# survival_rate 라는 함수가 agg에 내장 되어있는건가?
# 비율을 구해주네.
titanic.groupby('sex').agg({'survived':['sum', 'mean'], 'age':'mean'})
'''
survived age
sum mean mean
sex
female 233 0.742038 27.915709
male 109 0.188908 30.726645
'''
titanic.groupby('sex').agg(survived_total = ('survived', 'sum'),
survival_rate = ('survived', 'mean'), mean_age = ('age', 'mean'))
'''
survived_total survival_rate mean_age
sex
female 233 0.742038 27.915709
male 109 0.188908 30.726645
'''
# 각 함수의 이름이 직관적이긴 하나, 정말 저런 함수들이 있다고?
# 의문이 들게끔 하는 이름이다.
# 하지만 결과적으로는 너무 잘 출력 된다.
# 저런 이름의 함수들이 있는게 아니라. 기본 원리는 a = 1+2라고 할때, a는 3이 되는 것과 마찬가지다.
# total에 있어서는 survived컬럼의 sum을 해준 숫자이므로, 자동으로 모든 수의 합. 즉, total이 나오며
# mean에 있어서는 구성비율을 나타내게 된다.
## Transformation with transform()
import pandas as pd
titanic = pd.read_csv('titanic.csv')
titanic.head()
'''
survived pclass sex age sibsp parch fare embarked deck
0 0 3 male 22.0 1 0 7.2500 S NaN
1 1 1 female 38.0 1 0 71.2833 C C
2 1 3 female 26.0 0 0 7.9250 S NaN
3 1 1 female 35.0 1 0 53.1000 S C
4 0 3 male 35.0 0 0 8.0500 S NaN
'''
# 생존율 구하기
titanic.groupby(['sex', 'pclass']).survived.transform('mean')
'''
0 0.135447
1 0.968085
2 0.500000
3 0.968085
4 0.135447
...
886 0.157407
887 0.968085
888 0.500000
889 0.368852
890 0.135447
Name: survived, Length: 891, dtype: float64
'''
titanic.groupby(['sex', 'pclass']).survived.mean()
'''
sex pclass
female 1 0.968085
2 0.921053
3 0.500000
male 1 0.368852
2 0.157407
3 0.135447
Name: survived, dtype: float64
'''
titanic['group_surv_rate'] = titanic.groupby(['sex', 'pclass']).survived.transform('mean')
'''
0 0.135447
1 0.968085
2 0.500000
3 0.968085
4 0.135447
...
886 0.157407
887 0.968085
888 0.500000
889 0.368852
890 0.135447
Name: survived, Length: 891, dtype: float64
'''
titanic['outliers'] = abs(titanic.survived-titanic.group_surv_rate)
'''
0 0.135447
1 0.031915
2 0.500000
3 0.031915
4 0.135447
...
886 0.157407
887 0.031915
888 0.500000
889 0.631148
890 0.135447
Length: 891, dtype: float64
'''
# 0.85보다 큰 값을 필터링해서 출력
titanic.loc[titanic.outliers > 0.85]
'''
survived pclass sex age sibsp parch fare embarked deck group_surv_rate outliers
36 1 3 male NaN 0 0 7.2292 C NaN 0.135447 0.864553
41 0 2 female 27.00 1 0 21.0000 S NaN 0.921053 0.921053
65 1 3 male NaN 1 1 15.2458 C NaN 0.135447 0.864553
74 1 3 male 32.00 0 0 56.4958 S NaN 0.135447 0.864553
81 1 3 male 29.00 0 0 9.5000 S NaN 0.135447 0.864553
107 1 3 male NaN 0 0 7.7750 S NaN 0.135447 0.864553
125 1 3 male 12.00 1 0 11.2417 C NaN 0.135447 0.864553
127 1 3 male 24.00 0 0 7.1417 S NaN 0.135447 0.864553
146 1 3 male 27.00 0 0 7.7958 S NaN 0.135447 0.864553
165 1 3 male 9.00 0 2 20.5250 S NaN 0.135447 0.864553
177 0 1 female 50.00 0 0 28.7125 C C 0.968085 0.968085
199 0 2 female 24.00 0 0 13.0000 S NaN 0.921053 0.921053
204 1 3 male 18.00 0 0 8.0500 S NaN 0.135447 0.864553
207 1 3 male 26.00 0 0 18.7875 C NaN 0.135447 0.864553
220 1 3 male 16.00 0 0 8.0500 S NaN 0.135447 0.864553
261 1 3 male 3.00 4 2 31.3875 S NaN 0.135447 0.864553
267 1 3 male 25.00 1 0 7.7750 S NaN 0.135447 0.864553
271 1 3 male 25.00 0 0 0.0000 S NaN 0.135447 0.864553
283 1 3 male 19.00 0 0 8.0500 S NaN 0.135447 0.864553
286 1 3 male 30.00 0 0 9.5000 S NaN 0.135447 0.864553
297 0 1 female 2.00 1 2 151.5500 S C 0.968085 0.968085
301 1 3 male NaN 2 0 23.2500 Q NaN 0.135447 0.864553
312 0 2 female 26.00 1 1 26.0000 S NaN 0.921053 0.921053
338 1 3 male 45.00 0 0 8.0500 S NaN 0.135447 0.864553
348 1 3 male 3.00 1 1 15.9000 S NaN 0.135447 0.864553
357 0 2 female 38.00 0 0 13.0000 S NaN 0.921053 0.921053
391 1 3 male 21.00 0 0 7.7958 S NaN 0.135447 0.864553
400 1 3 male 39.00 0 0 7.9250 S NaN 0.135447 0.864553
414 1 3 male 44.00 0 0 7.9250 S NaN 0.135447 0.864553
429 1 3 male 32.00 0 0 8.0500 S E 0.135447 0.864553
444 1 3 male NaN 0 0 8.1125 S NaN 0.135447 0.864553
455 1 3 male 29.00 0 0 7.8958 C NaN 0.135447 0.864553
489 1 3 male 9.00 1 1 15.9000 S NaN 0.135447 0.864553
498 0 1 female 25.00 1 2 151.5500 S C 0.968085 0.968085
509 1 3 male 26.00 0 0 56.4958 S NaN 0.135447 0.864553
510 1 3 male 29.00 0 0 7.7500 Q NaN 0.135447 0.864553
553 1 3 male 22.00 0 0 7.2250 C NaN 0.135447 0.864553
569 1 3 male 32.00 0 0 7.8542 S NaN 0.135447 0.864553
579 1 3 male 32.00 0 0 7.9250 S NaN 0.135447 0.864553
622 1 3 male 20.00 1 1 15.7417 C NaN 0.135447 0.864553
643 1 3 male NaN 0 0 56.4958 S NaN 0.135447 0.864553
664 1 3 male 20.00 1 0 7.9250 S NaN 0.135447 0.864553
692 1 3 male NaN 0 0 56.4958 S NaN 0.135447 0.864553
709 1 3 male NaN 1 1 15.2458 C NaN 0.135447 0.864553
744 1 3 male 31.00 0 0 7.9250 S NaN 0.135447 0.864553
751 1 3 male 6.00 0 1 12.4750 S E 0.135447 0.864553
762 1 3 male 20.00 0 0 7.2292 C NaN 0.135447 0.864553
772 0 2 female 57.00 0 0 10.5000 S E 0.921053 0.921053
788 1 3 male 1.00 1 2 20.5750 S NaN 0.135447 0.864553
803 1 3 male 0.42 0 1 8.5167 C NaN 0.135447 0.864553
804 1 3 male 27.00 0 0 6.9750 S NaN 0.135447 0.864553
821 1 3 male 27.00 0 0 8.6625 S NaN 0.135447 0.864553
828 1 3 male NaN 0 0 7.7500 Q NaN 0.135447 0.864553
838 1 3 male 32.00 0 0 56.4958 S NaN 0.135447 0.864553
854 0 2 female 44.00 1 0 26.0000 S NaN 0.921053 0.921053
869 1 3 male 4.00 1 1 11.1333 S NaN 0.135447 0.864553
'''
## Replacing NA Values by group-specific Values
import pandas as pd
titanic = pd.read_csv('titanic.csv')
titanic.head(2)
'''
survived pclass sex age sibsp parch fare embarked deck
0 0 3 male 22.0 1 0 7.2500 S NaN
1 1 1 female 38.0 1 0 71.2833 C C
'''
titanic.info()
'''
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 survived 891 non-null int64
1 pclass 891 non-null int64
2 sex 891 non-null object
3 age 714 non-null float64
4 sibsp 891 non-null int64
5 parch 891 non-null int64
6 fare 891 non-null float64
7 embarked 889 non-null object
8 deck 203 non-null object
dtypes: float64(2), int64(4), object(3)
memory usage: 62.8+ KB
'''
titanic.age.mean()
# 29.69911764705882
# mean()은 다른것과 비교할만한 구성요소로써 작용할때는 구성비율
# 단일 컬럼으로써 작동할때는 '평균'의 의미가 있는 것 같다.
mean_age = titanic.age.mean()
# NaN 결측값을 age 평균으로 채워준다.
titanic.age.fillna(mean_age)
# 그렇지만 inplace = True를 해주어야 진정한 변경이 된다.
# 그 증거로
titanic.loc[titanic.age == 'NaN']
# 라고 aga의 값이 결측값인 행에 대해서 출력하라고 했을때 아무값도 안나온다.
titanic.groupby(['sex', 'pclass']).age.mean()
'''
sex pclass
female 1 34.611765
2 28.722973
3 21.750000
male 1 41.281386
2 30.740707
3 26.507589
Name: age, dtype: float64
'''
titanic['group_mean_age'] = titanic.groupby(['sex', 'pclass']).age.transform('mean')
'''
0 26.507589
1 34.611765
2 21.750000
3 34.611765
4 26.507589
...
886 30.740707
887 34.611765
888 21.750000
889 41.281386
890 26.507589
Name: age, Length: 891, dtype: float64
'''
titanic.head(2)
'''
survived pclass sex age sibsp parch fare embarked deck group_mean_age
0 0 3 male 22.0 1 0 7.2500 S NaN 26.507589
1 1 1 female 38.0 1 0 71.2833 C C 34.611765
'''
titanic.loc[titanic.age == 'NaN']
titanic.age.fillna(titanic.group_mean_age, inplace = True)
## Genenralizing split-apply-combine with apply()
import pandas as pd
titanic = pd.read_csv('titanic.csv', usecols = ['survived', 'pclass', 'sex', 'age', 'fare'])
titanic.head()
'''
survived pclass sex age fare
0 0 3 male 22.0 7.2500
1 1 1 female 38.0 71.2833
2 1 3 female 26.0 7.9250
3 1 1 female 35.0 53.1000
4 0 3 male 35.0 8.0500
'''
titanic.groupby('sex').mean()
'''
survived pclass age fare
sex
female 0.742038 2.159236 27.915709 44.479818
male 0.188908 2.389948 30.726645 25.523893
'''
## Generalizing split-apply-combine with apply()
import pandas as pd
titanic = pd.read_csv('titanic.csv', usecols = ['survived', 'pclass', 'sex', 'age', 'fare'])
titanic.head()
'''
survived pclass sex age fare
0 0 3 male 22.0 7.2500
1 1 1 female 38.0 71.2833
2 1 3 female 26.0 7.9250
3 1 1 female 35.0 53.1000
4 0 3 male 35.0 8.0500
'''
titanic.groupby('sex').mean()
'''
survived pclass age fare
sex
female 0.742038 2.159236 27.915709 44.479818
male 0.188908 2.389948 30.726645 25.523893
'''
female_group = list(titanic.groupby('sex'))[0][1]
'''
survived pclass sex age fare
1 1 1 female 38.0 71.2833
2 1 3 female 26.0 7.9250
3 1 1 female 35.0 53.1000
8 1 3 female 27.0 11.1333
9 1 2 female 14.0 30.0708
... ... ... ... ... ...
880 1 2 female 25.0 26.0000
882 0 3 female 22.0 10.5167
885 0 3 female 39.0 29.1250
887 1 1 female 19.0 30.0000
888 0 3 female NaN 23.4500
314 rows × 5 columns
'''
female_group.mean()
'''
survived 0.742038
pclass 2.159236
age 27.915709
fare 44.479818
dtype: float64
'''
def group_mean(group):
return group.mean()
group_mean(female_group)
'''
survived 0.742038
pclass 2.159236
age 27.915709
fare 44.479818
dtype: float64
'''
# groupby 객체에 적용하고자 하는 사용자 정의 함수 사용 방법
titanic.groupby('sex').apply(group_mean)
'''
survived pclass age fare
sex
female 0.742038 2.159236 27.915709 44.479818
male 0.188908 2.389948 30.726645 25.523893
'''
# mean은 근본적으로 평균 인것같다.
# 그래서 그 평균들이 뭉쳐있는 곳 사이에서 보이기를 비율처럼 보였을 수도 있고, 아닐수도있고
# 하지만 근본적으로 평균이다.
titanic.nlargest(5, 'age')
'''
survived pclass sex age fare
630 1 1 male 80.0 30.0000
851 0 3 male 74.0 7.7750
96 0 1 male 71.0 34.6542
493 0 1 male 71.0 49.5042
116 0 3 male 70.5 7.7500
'''
# 생존자 중에서 나이가 많은 순서대로 5명을 구하는 것
def five_oldest_surv(group):
return group[group.survived == 1].nlargest(5, 'age')
titanic.groupby('sex').apply(five_oldest_surv)
'''
survived pclass sex age fare
sex
female 275 1 1 female 63.0 77.9583
483 1 3 female 63.0 9.5875
829 1 1 female 62.0 80.0000
366 1 1 female 60.0 75.2500
11 1 1 female 58.0 26.5500
male 630 1 1 male 80.0 30.0000
570 1 2 male 62.0 10.5000
587 1 1 male 60.0 79.2000
647 1 1 male 56.0 35.5000
449 1 1 male 52.0 30.5000
'''
## Hierarchical Indexing (MultiIndex) with Groupby
- Hierarchical는 '계급에 따른' 이라는 뜻이다.
import pandas as pd
titanic = pd.read_csv('titanic.csv', usecols = ['survived', 'pclass', 'sex', 'age', 'fare'])
titanic
'''
survived pclass sex age fare
0 0 3 male 22.0 7.2500
1 1 1 female 38.0 71.2833
2 1 3 female 26.0 7.9250
3 1 1 female 35.0 53.1000
4 0 3 male 35.0 8.0500
... ... ... ... ... ...
886 0 2 male 27.0 13.0000
887 1 1 female 19.0 30.0000
888 0 3 female NaN 23.4500
889 1 1 male 26.0 30.0000
890 0 3 male 32.0 7.7500
891 rows × 5 columns
'''
summary = titanic.groupby(['sex', 'pclass']).mean()
'''
survived age fare
sex pclass
female 1 0.968085 34.611765 106.125798
2 0.921053 28.722973 21.970121
3 0.500000 21.750000 16.118810
male 1 0.368852 41.281386 67.226127
2 0.157407 30.740707 19.741782
3 0.135447 26.507589 12.661633
'''
summary.index
'''
MultiIndex([('female', 1),
('female', 2),
('female', 3),
( 'male', 1),
( 'male', 2),
( 'male', 3)],
names=['sex', 'pclass'])
'''
summary.loc[('female', 2),:]
'''
survived 0.921053
age 28.722973
fare 21.970121
Name: (female, 2), dtype: float64
'''
# summary.loc[['female', 2],:]
# 라고 하니깐, 2는 인덱스에 안들어있다면서 keyerror가 떴다.
summary.loc[('female', 2), 'age']
# 28.722972972972972
summary.swaplevel().sort_index()
'''
survived age fare
pclass sex
1 female 0.968085 34.611765 106.125798
male 0.368852 41.281386 67.226127
2 female 0.921053 28.722973 21.970121
male 0.157407 30.740707 19.741782
3 female 0.500000 21.750000 16.118810
male 0.135447 26.507589 12.661633
'''
summary.reset_index()
'''
sex pclass survived age fare
0 female 1 0.968085 34.611765 106.125798
1 female 2 0.921053 28.722973 21.970121
2 female 3 0.500000 21.750000 16.118810
3 male 1 0.368852 41.281386 67.226127
4 male 2 0.157407 30.740707 19.741782
5 male 3 0.135447 26.507589 12.661633
'''
## stack() and unstack()
import pandas as pd
summer = pd.read_csv('summer.csv')
summer.head()
'''
Year City Sport Discipline Athlete Country Gender Event Medal
0 1896 Athens Aquatics Swimming HAJOS, Alfred HUN Men 100M Freestyle Gold
1 1896 Athens Aquatics Swimming HERSCHMANN, Otto AUT Men 100M Freestyle Silver
2 1896 Athens Aquatics Swimming DRIVAS, Dimitrios GRE Men 100M Freestyle For Sailors Bronze
3 1896 Athens Aquatics Swimming MALOKINIS, Ioannis GRE Men 100M Freestyle For Sailors Gold
4 1896 Athens Aquatics Swimming CHASAPIS, Spiridon GRE Men 100M Freestyle For Sailors Silver
'''
medals_by_country = summer.groupby(['Country', 'Medal']).Medal.count()
'''
Country Medal
AFG Bronze 2
AHO Silver 1
ALG Bronze 8
Gold 5
Silver 2
..
ZIM Gold 18
Silver 4
ZZX Bronze 10
Gold 23
Silver 15
Name: Medal, Length: 347, dtype: int64
'''
medals_by_country.shape
# (347,)
medals_by_country.unstack()
'''
Medal Bronze Gold Silver
Country
AFG 2.0 NaN NaN
AHO NaN NaN 1.0
ALG 8.0 5.0 2.0
ANZ 5.0 20.0 4.0
ARG 91.0 69.0 99.0
... ... ... ...
VIE NaN NaN 2.0
YUG 118.0 143.0 174.0
ZAM 1.0 NaN 1.0
ZIM 1.0 18.0 4.0
ZZX 10.0 23.0 15.0
147 rows × 3 columns
'''
# level = -1이라는 의미는 -1까지 수준의 값을
# 가장 오른쪽에 있는 값을
# fill_value로써 채워준다는 뜻이다.
medals_by_country = medals_by_country.unstack(level = -1, fill_value = 0)
'''
Medal Bronze Gold Silver
Country
AFG 2 0 0
AHO 0 0 1
ALG 8 5 2
ANZ 5 20 4
ARG 91 69 99
... ... ... ...
VIE 0 0 2
YUG 118 143 174
ZAM 1 0 1
ZIM 1 18 4
ZZX 10 23 15
147 rows × 3 columns
'''
medals_by_country.shape
# (147, 3)
medals_by_country = medals_by_country[['Gold', 'Silver', 'Bronze']]
'''
Medal Gold Silver Bronze
Country
AFG 0 0 2
AHO 0 1 0
ALG 5 2 8
ANZ 20 4 5
ARG 69 99 91
... ... ... ...
VIE 0 2 0
YUG 143 174 118
ZAM 0 1 1
ZIM 18 4 1
ZZX 23 15 10
147 rows × 3 columns
'''
medals_by_country.sort_values(by = ['Gold', 'Silver', 'Bronze'], ascending= [False, False, False], inplace = True)
# ascending 에 False를 하나만 넣어주었더니
# ValueError: Length of ascending (1) != length of by (3)
# 에러가 나왔다.
medals_by_country.head()
'''
Medal Gold Silver Bronze
Country
USA 2235 1252 1098
URS 838 627 584
GBR 546 621 553
ITA 476 416 404
GER 452 378 475
'''
medals_by_country.loc[('USA', 'Gold')]
# 2235
import matplotlib.pyplot as plt
plt.style.use('seaborn')
medals_by_country.head(10).plot(kind = 'bar', figsize = (14,10), fontsize = 14)
plt.xlabel('Country', fontsize = 14)
plt.ylabel('Medals', fontsize = 14)
plt.title('Medals per Country', fontsize = 15)
plt.legend(fontsize = 15)
plt.show()
# 이번챕터를 통해서 이해가 안된 것
apply
- 함수적용의 연결고리 같은건데 형식은
df.apply(선언함수)
이렇게 사용된다.
그러면 선언함수에 df의 각각의 행에 해당하는 값이 들어가서
나오게 된다.
transform
agg
이 두개는 같이 가는 게 좋다.
agg는 nunique의 개념과도 흡사하다.
# 한 개념당의 점수만 보여준다.
# 하지만 transform은 각 개념에 대해서 값을 구해주고, 나열된 행만큼 출력이 된다.
df1
'''
이름 과목 점수 과목평균
0 송중기 국어 89 86.00
1 김나현 영어 42 47.00
2 박효신 국어 78 86.00
3 김범수 영어 61 47.00
4 권보아 국어 91 86.00
5 한동근 영어 38 47.00
'''
## agg
df1.groupby('과목')['점수'].agg('mean')
'''
과목
국어 86.00
영어 47.00
Name: 점수, dtype: float64
'''
# transform
df1['과목평균'] = df1.groupby('과목')['점수'].transform('mean')
'''
0 86.00
1 47.00
2 86.00
3 47.00
4 86.00
5 47.00
Name: 점수, dtype: float64
'''
# agg merge 버전 merge
df4= df2.groupby('과목')['점수'].agg('mean').reset_index()
df2.merge(df4, on = '과목', how = 'left')
'''
이름 과목 점수_x 점수_y
0 송중기 국어 89 86.00
1 김나현 영어 42 47.00
2 박효신 국어 78 86.00
3 김범수 영어 61 47.00
4 권보아 국어 91 86.00
5 한동근 영어 38 47.00
'''
# agg는 입력 후 출력하기는 쉽지만
# 뒷처리가 필요하다. 이를테면 컬럼명이 점수_x, 점수_y로 자동으로 반영되 나오기 때문이다.
# transform 버전 merge
# 반면, transform 은 컬럼명 지정이 가능하다.
# 익숙해지기가 약간 번거로울 뿐이지, 익숙해지고 나면 오히려 편하다.
# 평균과 표준편차를 더한 값을 리턴해줘라.
df3['m+s'] = df3.groupby('과목')['점수'].transform(lambda x:x.mean() + x.std())
'''
0 93.00
1 59.29
2 93.00
3 59.29
4 93.00
5 59.29
Name: 점수, dtype: float64
'''
# transform 필터
df3.loc[df3.groupby('과목')['점수'].transform(lambda x:x > x.mean())]
'''
이름 과목 점수 m+s
0 송중기 국어 89 93.00
3 김범수 영어 61 59.29
4 권보아 국어 91 93.00
'''
swaplevel
# 정보가 많이 없다. 패스하자.
unstack
stack
# 흠.. 시간을 두고 더 공부해보자. 이것도 난해하다.
300x250
'개발일지 > Pandas' 카테고리의 다른 글
pandas 판다스 기초 20, crosstab, melt, pivot_table (0) | 2022.08.15 |
---|---|
pandas 틀린문제 9, groupby, unstack, nlargest (0) | 2022.08.12 |
pandas 틀린부분 복기8 merge, add, 등 2개 이상의 파일 붙이고, 가공하기 (0) | 2022.08.08 |
pandas 판다스 기초 18 merge, join, fillna, drop (0) | 2022.08.08 |
pandas 판다스 틀린부분 복기 7 데이터 정리하기 (0) | 2022.08.01 |