데이터 분석/자료구조(Data structure)

파이썬 - Pandas 기초 정리(DataFrame - 3) : inner join / outer join

Jerry Jun 2020. 12. 23. 15:03
728x90

이제 정말 유용하게 사용되는 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 사진

그룹화를 하면 인덱스가 설정되어 초기 데이터프레임의 모양이 바뀌는 현상이 일어난다. 하지만 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]})

dataframe1
dataframe2

병합을 하기 전 2개의 데이터프레임을 만들었다.

(1) inner join

pd.merge(df1, df2, on = 'key')

inner join

'key' 를 기준으로 inner join 을 한 결과이다. 두 데이터 프레임이 공통적으로 가지고 있는 2,3,5 행만 가져온 모습을 볼 수 있다.

 

(2) left outer join

pd.merge(df1, df2, on = 'key', how = 'left')

left outer join

left outer join 의 결과이다. left 를 기준으로 했으므로 df1 의 모든 데이터를 가져왔고 df2 에 대해 없는 값은 NaN 으로 대체된 것을 볼 수 있다.

 

 

(3) right outer join

pd.merge(df1, df2, on = 'key', how = 'right')

right outer join

right outer join 의 결과이다. right 를 기준으로 했으므로 df2 의 모든 데이터를 가져왔고 df1에 어벗는 값은 NaN 으로 대체되었다. 

 

(4) full outer join

pd.merge(df1, df2, on = 'key', how = 'outer')

full outer join

full outer join 을 한 결과이다. left join 과 right join 이 합쳐진 결과라고 볼 수 있다.

300x250