이제 정말 유용하게 사용되는 Groupby 에 대해 알아볼 차례이다.
이 게시물은 이전 게시물들과 이어진다. (타이타닉 데이터 사용)
# groupby
df.groupby('Pclass').groups
---------------------------------
{1: Int64Index([ 2, 4, 7, 12, 24, 28, 31, 32, 35, 36,
...
854, 857, 858, 863, 868, 872, 873, 880, 888, 890],
dtype='int64', name='PassengerId', length=216),
2: Int64Index([ 10, 16, 18, 21, 22, 34, 42, 44, 54, 57,
...
849, 855, 862, 865, 866, 867, 875, 881, 884, 887],
dtype='int64', name='PassengerId', length=184),
3: Int64Index([ 1, 3, 5, 6, 8, 9, 11, 13, 14, 15,
...
876, 877, 878, 879, 882, 883, 885, 886, 889, 891],
dtype='int64', name='PassengerId', length=491)}
groupby 의 형태는 딕셔너리 형식으로 이루어진다. 위 코드와 같이 Pclass 를 기준으로 하였을 때 1,2,3 종류가 있으므로 key 에 3가지가 들어간다. 그리고 각자 키에 맞게 인덱스가 value 로 이루어진다. 이러한 groupby 를 통하여 그룹별로 계산한 데이터들을 볼 수 있다.
# 그룹 데이터 적용 가능 함수
-
count : 데이터 개수
-
min / max : 최소값 / 최대값
-
sum : 데이터 합계
-
mean / std / var : 평균 / 표준편차 / 분산
class_group = df.groupby('Pclass')
class_group.count()
대표적으로 count( ) 함수를 실행해보았다. 'Pclass' 를 기준으로 나누었더니 1등급은 216명이 살아남고 2등급은 184명, 3등급은 491명이 살아남은 것을 볼 수 있다. 같은 방식으로 다른 종류의 함수를 실행하면 데이터프레임이 나타난다.
# 다수의 함수 한번에 사용하기
df.set_index(['Pclass', 'Sex']).groupby(level=[0, 1]).aggregate([np.sum, np.max])
적용하고자 하는 함수가 많을 때 한번에 적용시키기 위해 사용하는 것이 aggregate( ) 이다. 코드를 보면 'Pclass' 와 'Sex' 를 인덱스로 설정하고 groupby 를 통해 인덱스 두개를 그룹화한다. level = 0 은 'Pclass' 이고 1 은 'Sex' 이다. 그리고 aggregate 를 통해 합계와 최대값을 넣어 출력하게 되었다.
# 데이터 프레임 형태 유지하기
df.groupby(['Pclass', 'Sex']).transform(np.mean)
그룹화를 하면 인덱스가 설정되어 초기 데이터프레임의 모양이 바뀌는 현상이 일어난다. 하지만 transform( )을 이용한다면 그룹화한 컬럼 표시가 사라지고 그 결과만 데이터프레임에 나타나게 된다. 이런 기능이 있는 함수도 있다는 것을 알고 넘어간다.
# 데이터 프레임 병합하기
df1 = pd.DataFrame({'순서' : np.arange(1, 11), '값' : np.random.randn(10)})
df2 = pd.DataFrame({'순서' : np.arange(1, 11), '값' : np.random.randn(10)})
데이터 병합을 보여주기에 앞서서 타이타닉 데이터 보다는 소규모의 데이터 프레임을 만들어 보여주는 것이 좋기 때문에 2개의 데이터프레임을 만들었다.
pd.concat([df1, df2])
concat( ) 을 이용하여 두 개의 데이터프레임을 병합하였더니 행 기준으로 쌓인 모습을 볼 수 있다. 인덱스 또한 영향을 받지 않고 그대로 쌓인 모습을 볼 수 있다. 하지만 이렇게 되면 나중에 인덱스를 사용하여 무언가를 하고 싶을 때 문제가 될 수 있으니 ignore_index 속성을 사용해 해결할 수 있다. 또한, 키의 값이 같아도 axis 속성을 이용해서 행 기준으로 쌓이지 않게 만들 수 있다.
df3 = pd.DataFrame({'다른이름' : np.arange(1, 12), '값' : np.random.randn(11)})
pd.concat([df1, df2, df3], ignore_index=True)
그렇다면 다른 이름을 가진 컬럼을 가지면 어떻게 될 지 실행해보았다. ingore_index 를 True 로 놓았고, 컬럼명을 다르게 했더니 열이 하나 더 생기고 값이 없는 것은 NaN 이 반환되는 것을 알 수 있었다.
# Merge | Join
- Join 의 종류
- inner join : default. 일치하는 값이 있는 경우
- left outer join
- right outer join
- full outer join
기준을 두고 병합하는 것이 효율적이기 때문에 앞서 나온 concat 보다는 join 을 통해 많이 병합한다.
df1 = pd.DataFrame({'key' : [1,2,3,4,5], 'name' : ['철수', '영희', '바둑이', '민수', '나래'], '재산' : [100, 200, 500, 400, 700]})
df2 = pd.DataFrame({'key' : [3,5,2,7,6], 'car' : ['tico', 'sonata', 'truck', 'benz', 'morning'], 'year' : [2007,2010,2005,2015,2017]})
병합을 하기 전 2개의 데이터프레임을 만들었다.
(1) inner join
pd.merge(df1, df2, on = 'key')
'key' 를 기준으로 inner join 을 한 결과이다. 두 데이터 프레임이 공통적으로 가지고 있는 2,3,5 행만 가져온 모습을 볼 수 있다.
(2) left outer join
pd.merge(df1, df2, on = 'key', how = 'left')
left outer join 의 결과이다. left 를 기준으로 했으므로 df1 의 모든 데이터를 가져왔고 df2 에 대해 없는 값은 NaN 으로 대체된 것을 볼 수 있다.
(3) right outer join
pd.merge(df1, df2, on = 'key', how = 'right')
right outer join 의 결과이다. right 를 기준으로 했으므로 df2 의 모든 데이터를 가져왔고 df1에 어벗는 값은 NaN 으로 대체되었다.
(4) full outer join
pd.merge(df1, df2, on = 'key', how = 'outer')
full outer join 을 한 결과이다. left join 과 right join 이 합쳐진 결과라고 볼 수 있다.
'데이터 분석 > 자료구조(Data structure)' 카테고리의 다른 글
파이썬 - Pandas 기초 정리(DataFrame - 2) (0) | 2020.12.23 |
---|---|
파이썬 - Pandas 기초 정리(DataFrame - 1) (0) | 2020.12.22 |
파이썬 - Pandas 기초 정리(Series) (0) | 2020.12.21 |
파이썬 - Numpy 기초 정리(2) (0) | 2020.12.17 |
파이썬 - Numpy 기초 정리(1) (0) | 2020.12.16 |