데이터시각화 특강 (8주차) 11월1일 _2
barplot, 해들리위컴의 그래프레이어, 심슨의역설
import pandas as pd
import numpy as np
from plotnine import *
import matplotlib.pyplot as plt
g=['A']*100+['B']*200
y=list(np.random.randn(100)*2+2)+list(np.random.randn(200)+3)
df=pd.DataFrame({'g':g,'y':y})
df
ggplot(df)+geom_bar(aes(x='g',fill='g')) ## 디폴트로 카운트를 수행해줌
-
이것은 아래의 코드와 같다.
df.groupby(by='g').count()
fig=ggplot(df.groupby(by='g').count().reset_index()) # 데이터 정리 후 ggplot사용
fig+geom_bar(aes(x='g',y='y',fill='g'),stat='identity') # 아무런 변환하지 않는다는 stat=identity
-
barplot은 기본적으로 groupby+count()가 내장되어 있다. 따라서 아래의 코드
ggplot(df)+geom_bar(aes(x='g',fill='g')) ## 디폴트로 카운트를 수행해줌
를 좀더 엄밀하게 쓰면
ggplot(df)+geom_bar(aes(x='g',fill='g'),stat='count')
-
이것은 때때로 불편하다. 왜냐하면 데이터프레임을 변환하는 것은 판다스를 이용하는게 더 쉽고 자유로움
td=df.groupby(by='g').count().reset_index()
td
-
그냥 'x=g, y=y'를 맵핑하여 그리면 안되나?
plt.bar(td.g,td.y)
td.plot(kind='bar',x='g',y='y')
-
그런데 ggplot을 쓰려고 하면?
ggplot(td)+geom_bar(aes(x='g',y='y',fill='g'))
ggplot(td)+geom_bar(aes(x='g',y='y',fill='g'),stat='identity')
- 너무 불편해요.. stat='identity' 를 항상 써야하는것이!
-
groupby 를 자동으로 해주므로 익숙해지면 ggplot2 방식이 더 편하지 않을까? $\to$ groupby 하는게 더 편해요..
df.groupby('g').agg({'y':[np.mean,np.median,np.std,lambda x: np.max(x)-np.min(x)]})
df.groupby('g')\
.agg({'y':[np.mean,np.median,np.std,lambda x: np.max(x)-np.min(x)]})\
.rename(columns={'<lambda_0>':'range'}).stack().reset_index()
td=df.groupby('g')\
.agg({'y':[np.mean,np.median,np.std,lambda x: np.max(x)-np.min(x)]})\
.rename(columns={'<lambda_0>':'range'}).stack().reset_index()
ggplot(td)+geom_bar(aes(x='level_1',y='y',fill='g'),stat='identity')
- 쌓인상태로 보이는것이 불편함. $\to$ position='dodge' 로!
ggplot(td)+geom_bar(aes(x='level_1',y='y',fill='g'),stat='identity',position='dodge')
-
때때로 아래와 같이 보는 것이 더 좋은 경우도 있음
ggplot(td)\
+geom_bar(aes(x='level_1',y='y',fill='g'),stat='identity',position='dodge')\
+coord_flip()
ggplot(td)\
+geom_bar(aes(x='level_1',y='y',fill='g'),stat='identity',position='dodge')\
+coord_flip()+facet_wrap('level_1')
ggplot(td)\
+geom_bar(aes(x='g',y='y',fill='g'),stat='identity',position='dodge')\
+coord_flip()+facet_wrap('level_1')
ggplot(td)+facet_grid('level_1~g')\
+geom_bar(aes(x='g',y='y',fill='g'),stat='identity',position='dodge')+coord_flip()
-
데이터셋 + 맵핑 + 지옴 + 포지션 + 스탯 + 축 + 면분할
- 데이터셋: 판다스
- 맵핑: x축, y축, 색깔, 크기, 투명도
- 지옴: 포인트지옴, 바지옴, 라인지옴, 스무스지옴
- 포지션: jitter, dodge, intentity
- 스탯: identity, count
- 축: coord_flip()
- 면분할: facet_wrap(), facet_grid()
DEP=(['A1']*2+['A2']*2+['B1']*2+['B2']*2)*2
GEN=['M']*8+['F']*8
STATE=['PASS','FAIL']*8
COUNT=[1,9,2,8,80,20,85,15,5,5,5,5,9,1,9,1]
df=pd.DataFrame({'DEP':DEP,'STATE':STATE,'GEN':GEN,'COUNT':COUNT})
df
df.groupby(['GEN','STATE']).agg({'COUNT':np.sum})
df.groupby(['GEN','STATE']).agg({'COUNT':np.sum})
df.groupby(['GEN','STATE']).agg({'COUNT':np.sum}).reset_index()
df.groupby(['GEN']).agg({'COUNT':np.sum}).reset_index()
-
두개의 데이터프레임을 합쳐야 한다.
_df1=df.groupby(['GEN','STATE']).agg({'COUNT':np.sum}).reset_index()
_df2=df.groupby(['GEN']).agg({'COUNT':np.sum}).reset_index().rename(columns={'COUNT':'SUM'})
display(_df1)
display(_df2)
-
단순한 방법
def f(x):
if x=='F':
return 40
if x=='M':
return 220
_df1['SUM']=list(map(f,_df1.GEN))
_df1
-
좀 더 좋은 방법
_df1=df.groupby(['GEN','STATE']).agg({'COUNT':np.sum}).reset_index()
- _df1를 다시 롤백
def f(_df2):
return lambda x: _df2.query('GEN == @x').SUM.item()
_df1.GEN
_df1['SUM']=list(map(f(_df2),_df1.GEN))
_df1
-
더 좋은 방법
_df1=df.groupby(['GEN','STATE']).agg({'COUNT':np.sum}).reset_index()
- _df1을 다시 롤백
_df1
_df2
pd.merge(_df1,_df2)
_df1.merge(_df2)
_df2.merge(_df1)
td=_df2.merge(_df1)
td
td['PROP']=td.COUNT/td.SUM
td
ggplot(td.query('STATE=="PASS"'))+geom_bar(aes(x='GEN',y='PROP',fill='GEN'),stat='identity')
-
남자의 합격률이 더 높다. $\to$ 성차별이 있어보인다(?)
-
학과별 합격률
df
td=df.groupby(['DEP','GEN']).agg({'COUNT':sum}).reset_index()\
.rename(columns={'COUNT':'SUM'}).merge(df)
td['PROP']=td.COUNT/td.SUM
td
td.query('STATE=="PASS"')
ggplot(td.query('STATE=="PASS"'))\
+geom_bar(aes(x='GEN',y='PROP',fill='GEN'),stat='identity')\
+facet_wrap('DEP')