일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- Python
- Linear Regression
- 경사하강법
- GitHub
- 주피터노트북
- feature scaling
- deep learning
- 주피터 노트북 테마
- Git
- 회귀분석
- jupytertheme
- 모두를 위한 딥러닝
- 주피터테마
- overfitting
- MySQL
- 한빛미디어
- random forest
- 주피터노트북 커널 목록
- Machine Learning
- 주피터노트북 커널 추가
- pandas
- ubuntu
- deeplearning
- 데이터분석
- regression
- Udacity
- 딥러닝
- 주피터노트북 커널 제거
- lol api
- 나는리뷰어다2021
- Today
- Total
유승훈
Python(3) - Concat 본문
1. Concat
전에 올린 글에서도 말했듯 데이터는 언제나 원하는 모양이나 형태로 오지 않습니다. 또 항상 하나로 오지도 않습니다. 여러개로 나뉘어 오기도 하죠. 날짜, 시간별로 생성되기 때문일수도 있고, 용량이 크기 때문에 일부러 나누기도 합니다. 그래서 데이터를 합칠수도, 나눌수도 있어야합니다. 여러 파일에 같은 처리를 한번에 하거나, 합쳐서 처리한 다음 나누기도 합니다.
Pandas에서 데이터를 합칠때 사용하는것이 concat입니다. 기본적으로 합칠 데이터프레임을 리스트 형태로 입력합니다.
경우에 따라 데이터를 행으로 연결하기도, 열로 연결하기도 합니다. 이때 axis로 붙일 방향을 변경할수있습니다. default로 axis는 0으로 되어있어 행으로 데이터를 병합하지만, 1로 넣으면 열로 데이터를 연결합니다. 행으로 붙일때는 열의 이름이 같을때, 열로 붙일때는 행의 인덱스가 같을때 동일한 행으로 합쳐집니다.
# example data
df_a
name treat_a treat_b
0 Daniel 0 42
1 John 12 31
2 Jane 24 27
df_b
name treat_c treat_d
0 Daniel 9 23
1 John 32 52
2 Jane 15 10
3 James 23 32
# axis
## axis=1
pd.concat([df_a,df_b],axis=1)
name treat_a treat_b name treat_c treat_d
0 Daniel 0.0 42.0 Daniel 9 23
1 John 12.0 31.0 John 32 52
2 Jane 24.0 27.0 Jane 15 10
3 NaN NaN NaN James 23 32
# axis=0
pd.concat([df_a,df_b],axis=0)
name treat_a treat_b treat_c treat_d
0 Daniel 0.0 42.0 NaN NaN
1 John 12.0 31.0 NaN NaN
2 Jane 24.0 27.0 NaN NaN
0 Daniel NaN NaN 9.0 23.0
1 John NaN NaN 32.0 52.0
2 Jane NaN NaN 15.0 10.0
3 James NaN NaN 23.0 32.0
다음은 join입니다. 데이터를 연결하는 것이기 때문에 이름이 같은 컬럼도, 다른 컬럼도 존재할수있습니다. concat에서는 join을 inner, outer로 넣을수있습니다. inner join은 table1과 table2가 둘 다 가지고 있는 교집합을 의미합니다. concat에서 join을 inner로 넣으면 axis가 0일때에는 이름이 일치하는 컬럼에 대해서만 병합합니다. axis를 1로 하면 두 데이터 중 작은 길이(행)의 데이터에 맞게 긴 데이터를 잘라붙입니다.
outer join은 한 테이블을 기준으로 두고 join하는 테이블과 매치되는 데이터가 있는 경우에는 붙이고, 없는 경우에는 NULL값으로 두는 방식입니다. concat에서 join을 outer로 넣으면 axis에 상관없이 table1, table2 모든 데이터를 병합하되, 연결한 컬럼에 데이터가 없는 경우 NaN으로 처리합니다. 다른건 행으로 붙이는가 열로 붙이는가뿐입니다. join의 default값은 outer입니다.
합친 데이터를 보면, 행과 열의 인덱스가 합치기 전의 데이터 그대로 남아있는것을 볼수있습니다. 그대로 쓴다면 상관없지만, 행 인덱스가 뒤죽박죽이거나 열 이름이 중복되는 경우 처리할때 불편할수있습니다. 이럴때 인데스를 ignore_index로 처리해줄수있습니다. ignore_index는 처음에는 false지만, True로 넣으면 합친 데이터의 방향에 따른 인덱스를 초기화합니다. 즉 axis=1일때는 열 인덱스를, axis=0일때는 행 인덱스를 초기화합니다. 파이썬은 순서를 0부터 세기 때문에 초기화된 인덱스도 0부터 N(행, 열수)-1로 입력됩니다.
# join
## join='inner'
pd.concat([df_a,df_b],axis=0,join='inner')
name
0 Daniel
1 John
2 Jane
0 Daniel
1 John
2 Jane
3 James
pd.concat([df_a,df_b],axis=1,join='inner')
name treat_a treat_b name treat_c treat_d
0 Daniel 0 42 Daniel 9 23
1 John 12 31 John 32 52
2 Jane 24 27 Jane 15 10
## join='outer'
pd.concat([df_a,df_b],axis=0,join='outer')
name treat_a treat_b treat_c treat_d
0 Daniel 0.0 42.0 NaN NaN
1 John 12.0 31.0 NaN NaN
2 Jane 24.0 27.0 NaN NaN
0 Daniel NaN NaN 9.0 23.0
1 John NaN NaN 32.0 52.0
2 Jane NaN NaN 15.0 10.0
3 James NaN NaN 23.0 32.0
pd.concat([df_a,df_b],axis=1,join='outer')
name treat_a treat_b name treat_c treat_d
0 Daniel 0.0 42.0 Daniel 9 23
1 John 12.0 31.0 John 32 52
2 Jane 24.0 27.0 Jane 15 10
3 NaN NaN NaN James 23 32
합친 데이터를 보면, 행과 열의 인덱스가 합치기 전의 데이터 그대로 남아있는것을 볼수있습니다. 그대로 쓴다면 상관없지만, 행 인덱스가 뒤죽박죽이거나 열 이름이 중복되는 경우 처리할때 불편할수있습니다. 이럴때 인데스를 ignore_index로 처리해줄수있습니다. ignore_index는 처음에는 false지만, True로 넣으면 합친 데이터의 방향에 따른 인덱스를 초기화합니다. 즉 axis=1일때는 열 인덱스를, axis=0일때는 행 인덱스를 초기화합니다. 파이썬은 순서를 0부터 세기 때문에 초기화된 인덱스도 0부터 N(행, 열수)-1로 입력됩니다.
# ignore_index
## ignore_index=True
pd.concat([df_a,df_b],axis=0,join='outer',ignore_index=True)
name treat_a treat_b treat_c treat_d
0 Daniel 0.0 42.0 NaN NaN
1 John 12.0 31.0 NaN NaN
2 Jane 24.0 27.0 NaN NaN
3 Daniel NaN NaN 9.0 23.0
4 John NaN NaN 32.0 52.0
5 Jane NaN NaN 15.0 10.0
6 James NaN NaN 23.0 32.0
pd.concat([df_a,df_b],axis=1,join='outer',ignore_index=True)
0 1 2 3 4 5
0 Daniel 0.0 42.0 Daniel 9 23
1 John 12.0 31.0 John 32 52
2 Jane 24.0 27.0 Jane 15 10
3 NaN NaN NaN James 23 32
위에서 봤던 데이터프레임들은 모두 하나의 인덱스만을 가지고 있습니다. 하지만 보다 자세한 인덱싱을 위해 하나의 인덱스가 아닌 계층적 인덱싱을 해줄수도 있습니다. 이때 keys 옵션을 활용합니다. concat에 입력한 데이터 개수만큼의 인덱스를 리스트나 튜플 등 순서가 있는 자료형으로 받습니다. keys를 통한 인덱싱도 axis 옵션에 따라 위치가 달라집니다. axis=1이 되어 열로 데이터를 붙이면 입력한 데이터의 컬럼명에 계층적 인덱싱을 하고, axis=0이 되어 행으로 데이터를 붙이면, 입력한 데이터의 열 이름에 계층적 인덱싱을 합니다. 입력한 데이터의 개수에 맞지 않게 입력하면 keys 길이의 데이터만 병합되므로 주의해야합니다.
# keys
## axis=1
pd.concat([df_a,df_b],keys=['a','b'],axis=1)
a b
name treat_a treat_b name treat_c treat_d
0 Daniel 0.0 42.0 Daniel 9 23
1 John 12.0 31.0 John 32 52
2 Jane 24.0 27.0 Jane 15 10
3 NaN NaN NaN James 23 32
## axis=0
pd.concat([df_a,df_b],keys=['a','b'],axis=0)
name treat_a treat_b treat_c treat_d
a 0 Daniel 0.0 42.0 NaN NaN
1 John 12.0 31.0 NaN NaN
2 Jane 24.0 27.0 NaN NaN
b 0 Daniel NaN NaN 9.0 23.0
1 John NaN NaN 32.0 52.0
2 Jane NaN NaN 15.0 10.0
3 James NaN NaN 23.0 32.0
우리가 인덱스를 설정할때, 입력할때와 실제 인덱스가 갖는 순서가 다른 경우가 있습니다. 이때 keys에는 순서대로 입력하고, levels에 인덱스가 실제로 갖는 순서를 categoricalindex로 만들어 넣어줍니다. 이렇게하면 인덱스가 제 위치에 잘 입력되고, 실제 순서도 index가 잘 인식하고 있음을 알수있습니다. 예시를 살펴보면 keys로 입력한 인덱스는 순서 그대로 들어가지만, level을 살펴보면 levels에 입력한대로 정렬되어있음을 볼수있습니다.
# levels
## axis=1
dff = pd.concat([df_a,df_b],axis=1,keys=['a','b'],levels=[['b','a']])
a b
name treat_a treat_b name treat_c treat_d
0 Daniel 0.0 42.0 Daniel 9 23
1 John 12.0 31.0 John 32 52
2 Jane 24.0 27.0 Jane 15 10
3 NaN NaN NaN James 23 32
dff.columns.levels
FrozenList([['b', 'a'], ['name', 'treat_a', 'treat_b', 'treat_c', 'treat_d']])
## axis=0
dff = pd.concat([df_a,df_b],axis=0,keys=['a','b'],levels=[['b','a']])
name treat_a treat_b treat_c treat_d
a 0 Daniel 0.0 42.0 NaN NaN
1 John 12.0 31.0 NaN NaN
2 Jane 24.0 27.0 NaN NaN
b 0 Daniel NaN NaN 9.0 23.0
1 John NaN NaN 32.0 52.0
2 Jane NaN NaN 15.0 10.0
3 James NaN NaN 23.0 32.0
dff.index.levels
FrozenList([['b', 'a'], [0, 1, 2, 3]])
names는 concat으로 만들어지는 다중 인덱스에 이름을 붙입니다. 다중 인덱스가 만들어지는 것은 axis에 따라서 달라지기 때문에 names도 당연히 axis에 따라 붙는 방향이 달라집니다. axis=0일때는 행에 다중 인덱스가 생성되므로 행에, axis=1일때는 열에 다중 인덱스가 생성되므로 열쪽에 이름이 있는것을 볼수있습니다.
# names
## axis=0
dff = pd.concat([df_a,df_b],axis=0,keys=['a','b'],levels=[['b','a']],names=['aaa','bbb'])
name treat_a treat_b treat_c treat_d
aaa bbb
a 0 Daniel 0.0 42.0 NaN NaN
1 John 12.0 31.0 NaN NaN
2 Jane 24.0 27.0 NaN NaN
b 0 Daniel NaN NaN 9.0 23.0
1 John NaN NaN 32.0 52.0
2 Jane NaN NaN 15.0 10.0
3 James NaN NaN 23.0 32.0
dff.index
MultiIndex([('a', 0),
('a', 1),
('a', 2),
('b', 0),
('b', 1),
('b', 2),
('b', 3)],
names=['aaa', 'bbb'])
## axis=1
dff = pd.concat([df_a,df_b],axis=1,keys=['a','b'],levels=[['b','a']],names=['aaa','bbb'])
aaa a b
bbb name treat_a treat_b name treat_c treat_d
0 Daniel 0.0 42.0 Daniel 9 23
1 John 12.0 31.0 John 32 52
2 Jane 24.0 27.0 Jane 15 10
3 NaN NaN NaN James 23 32
dff.columns
MultiIndex([('a', 'name'),
('a', 'treat_a'),
('a', 'treat_b'),
('b', 'name'),
('b', 'treat_c'),
('b', 'treat_d')],
names=['aaa', 'bbb'])
verify_integrity는 병합하고자 하는 두 데이터가 중복된 인덱스를 가지는지를 확인합니다. default는 false로 병합하는 데이터에서 인덱스가 겹치는 것을 허용합니다. True로 입력하면 행으로 합칠 경우(axis=0) 중복되는 행의 인덱스를, 열로 합칠 경우(axis=1) 중복되는 열의 인덱스를 허용하지 않습니다. 합치는 축이 아닌 인덱스는 중복을 허용합니다.
# verify_integrity=True
## axis=0
df_a.index
RangeIndex(start=0, stop=3, step=1)
df_b.index
RangeIndex(start=0, stop=4, step=1)
dff = pd.concat([df_a,df_b],axis=0,verify_integrity=True)
ValueError: Indexes have overlapping values: Int64Index([0, 1, 2], dtype='int64')
## change df_a.index
df_a.index = ['a1','a2','a3']
dff = pd.concat([df_a,df_b],axis=0,verify_integrity=True)
name name treat_a treat_b treat_c treat_d
a1 NaN Daniel 0.0 42.0 NaN NaN
a2 NaN John 12.0 31.0 NaN NaN
a3 NaN Jane 24.0 27.0 NaN NaN
0 John NaN NaN NaN 9.0 23.0
1 Jane NaN NaN NaN 32.0 52.0
2 Daniel NaN NaN NaN 15.0 10.0
3 James NaN NaN NaN 23.0 32.0
## axis=1
df_a.columns
Index(['name', 'treat_a', 'treat_b'], dtype='object')
df_b.columns
Index(['name', 'treat_c', 'treat_d'], dtype='object')
dff = pd.concat([df_a,df_b],axis=1,verify_integrity=True)
ValueError: Indexes have overlapping values: Index(['name'], dtype='object')
## change df_a.columns
df_a.columns = ['a1','a2','a3']
dff = pd.concat([df_a,df_b],axis=1,verify_integrity=True)
a1 a2 a3 name treat_c treat_d
a1 Daniel 0.0 42.0 NaN NaN NaN
a2 John 12.0 31.0 NaN NaN NaN
a3 Jane 24.0 27.0 NaN NaN NaN
0 NaN NaN NaN John 9.0 23.0
1 NaN NaN NaN Jane 32.0 52.0
2 NaN NaN NaN Daniel 15.0 10.0
3 NaN NaN NaN James 23.0 32.0
예시로 쓴 데이터는 예제로 만들었기 때문에 행렬의 정렬이 깔끔하지만, 그렇지 않은 경우도 있습니다. 그때 sort로 정렬해줄수있습니다.
# sort
## axis=0
pd.concat([df_b,df_a],axis=0)
name treat_c treat_d treat_a treat_b
0 John 9.0 23.0 NaN NaN
1 Jane 32.0 52.0 NaN NaN
2 Daniel 15.0 10.0 NaN NaN
3 James 23.0 32.0 NaN NaN
0 Daniel NaN NaN 0.0 42.0
1 John NaN NaN 12.0 31.0
2 Jane NaN NaN 24.0 27.0
pd.concat([df_b,df_a],axis=0,sort=True)
name treat_a treat_b treat_c treat_d
0 John NaN NaN 9.0 23.0
1 Jane NaN NaN 32.0 52.0
2 Daniel NaN NaN 15.0 10.0
3 James NaN NaN 23.0 32.0
0 Daniel 0.0 42.0 NaN NaN
1 John 12.0 31.0 NaN NaN
2 Jane 24.0 27.0 NaN NaN
## axis=1
pd.concat([df_b,df_a],axis=1,sort=False)
name treat_c treat_d name treat_a treat_b
b1 John 9.0 23.0 NaN NaN NaN
b2 Jane 32.0 52.0 NaN NaN NaN
b3 Daniel 15.0 10.0 NaN NaN NaN
b4 James 23.0 32.0 NaN NaN NaN
a1 NaN NaN NaN Daniel 0.0 42.0
a2 NaN NaN NaN John 12.0 31.0
a3 NaN NaN NaN Jane 24.0 27.0
pd.concat([df_b,df_a],axis=1,sort=True)
name treat_c treat_d name treat_a treat_b
a1 NaN NaN NaN Daniel 0.0 42.0
a2 NaN NaN NaN John 12.0 31.0
a3 NaN NaN NaN Jane 24.0 27.0
b1 John 9.0 23.0 NaN NaN NaN
b2 Jane 32.0 52.0 NaN NaN NaN
b3 Daniel 15.0 10.0 NaN NaN NaN
b4 James 23.0 32.0 NaN NaN NaN
계속 입력하던 df_a, df_b의 순서에서 반대로 df_b, df_a로 입력했습니다. sort는 합치는 축의 반대를 정렬합니다. 즉 행으로 합치면 열의 이름으로, 열로 합치면 행의 인덱스를 정렬하는 것입니다. axis가 0일때를 먼저 보면 기본 옵션은 sort=False일때는 name, treat_c, treat_d, treat_a, treat_b의 순서로 입력되어있다가, sort=True로 해주면 알파벳 순서대로 정렬되어 있는것을 볼수있습니다. axis를 1로 하여 열로 합치면 행의 인덱스로 데이터를 정렬합니다. (원래는 기본 인덱스인 숫자로 되어있었으나, 명확한 예시를 보여주기 위해서 임의로 모든 인덱스를 다르게 했습니다. sort=False일때는 입력한 데이터의 인덱스로 정렬되어 있으나, sort=True로 해주면 알파벳 순서대로 행의 인덱스가 정렬되어 있는것을 볼수있습니다.
지금까지 여러개로 나뉘어진 데이터를 하나로 합치는 concat에 대하여 정리했습니다. 같은 강의에 여러 데이터를 한번에 불러오는 glob이나 데이터를 비교해서 일치하는 데이터와 병합하는 merge에 대한 이야기도 있지만, 글이 너무 길어져서 나눠서 정리하고자 합니다.
'languages > Python' 카테고리의 다른 글
TypeError: 'float' object cannot be interpreted as an integer (2) | 2021.01.23 |
---|---|
카카오 API를 활용한 좌표->주소 변환하기(Python) (0) | 2020.12.21 |
Python(4) - glob, listdir (0) | 2020.03.17 |
Python(2) - Tidy data (0) | 2020.03.05 |
Python(1) - Basic Data attribute (0) | 2020.03.05 |