pd.DataFrame으로 이루어진 데이터에서
문자열로 이루어진 컬럼의 값들을
구분자를 이용해서
여러 개의 컬럼으로 나누는 방법을 소개합니다.
컬럼 단위로 split 하는 방법과
로우 단위로 split 하는 방법이 있다.
여기서는 하나의 cell 값을 기준으로
컬럼 단위로는 새로운 컬럼을 생성하면서
로우 단위로는 새로운 로우를 생성하면서
데이터프레임을 나누는 여러 가지 방법을 소개한다.
pd.read_csv를 통해 데이터를 불러오고나서
구분자가 섞여있거나 pandas가 인식못하는 경우,
데이터프레임의 구성이 혼잡하게 되어 있는 경우 사용하면 좋다.
전제조건:
1. 컬럼의 모든 값들은 문자열로 이루어져 있어야 한다.
2. 구분자로 사용할만한 개행 및 특수 문자들이 있어야 한다. ( '\t', ',', '_', ';', ':' ... 등등)
3. 하나의 셀 안에 여러 개의 값이 있어야 한다.
1. 컬럼 갯수가 적은 데이터 프레임
구분자를 이용해서 컬럼을 split 해주고,
컬럼 갯수가 적기 때문에
직접 컬럼 이름을 지정해주었다.
import pandas as pd
two_country_df = pd.DataFrame({'국가':['대한민국, 미국','대한민국,일본']})
two_country_df
국가
0 대한민국,미국
1 대한민국,일본
two_country_df[['나라_1','나라_2']] = two_country_df['국가'].str.split(',', expand=True)
two_country_df
국가 나라_1 나라_2
0 대한민국,미국 대한민국 미국
1 대한민국,일본 대한민국 일본
2. 특정 문자열을 기준으로하여 컬럼으로 사용하고 싶은 경우
여러가지 문자열이 하나의 컬럼에 있을 때,
그 중 특정 문자열을 기준 컬럼으로 잡고,
나머지 문자열을 다른 하나의 컬럼으로 몰고 싶을때 사용한다.
country_df = pd.DataFrame({'국가':['대한민국,미국,호주,영국','대한민국,일본,중국','대한민국,베트남','대한민국,필리핀','대한민국,독일,체코,러시아,영국']})
country_df
국가
0 대한민국,미국,호주,영국
1 대한민국,일본,중국
2 대한민국,베트남
3 대한민국,필리핀
4 대한민국,독일,체코,러시아,영국
country_df[['우리나라', '나머지국가']] = country_df['국가'].str.split(',', 1, expand=True)
country_df = country_df.drop(columns=['국가'])
country_df
우리나라 나머지국가
0 대한민국 미국,호주,영국
1 대한민국 일본,중국
2 대한민국 베트남
3 대한민국 필리핀
4 대한민국 독일,체코,러시아,영국
3. 여러개의 컬럼으로 split하고나서 원하는 컬럼만 하나로 묶고 싶을 때
하나의 컬럼을 구분자를 기준으로 여러 컬럼으로 split하는 과정에서,
add_prefix 메서드를 통하여 반복 컬럼을 컨트롤 할 수 있다.
그리고 컬럼 인덱스를 지정해줌으로써,
원하는 컬럼만 모아서 합쳐줄 수 있다.
country_df = pd.DataFrame({'국가':['대한민국,미국,호주,영국','대한민국,일본,중국','대한민국,베트남','대한민국,필리핀','대한민국,독일,체코,러시아,영국']})
country_df
국가
0 대한민국,미국,호주,영국
1 대한민국,일본,중국
2 대한민국,베트남
3 대한민국,필리핀
4 대한민국,독일,체코,러시아,영국
country_df['국가'].str.split(',', expand=True)
0 1 2 3 4
0 대한민국 미국 호주 영국 None
1 대한민국 일본 중국 None None
2 대한민국 베트남 None None None
3 대한민국 필리핀 None None None
4 대한민국 독일 체코 러시아 영국
### 컬럼을 2개 이상으로 multiple하게 split 해줄 때, prefix를 이용해서 컬럼 명을 지정해줄 수 있다.
country_df = country_df.join(country_df['국가'].str.split(',', expand=True).add_prefix('ID'))
country_df
국가 ID0 ID1 ID2 ID3 ID4
0 대한민국,미국,호주,영국 대한민국 미국 호주 영국 None
1 대한민국,일본,중국 대한민국 일본 중국 None None
2 대한민국,베트남 대한민국 베트남 None None None
3 대한민국,필리핀 대한민국 필리핀 None None None
4 대한민국,독일,이탈리아,러시아,영국,프랑스 대한민국 독일 체코 러시아 영국
### 컬럼 인덱스 2이상의 모든 컬럼을 합쳐서, 하나의 컬럼으로 만들기
country_df['나머지국가'] = country_df[country_df.columns[2:]].apply(
lambda x : ','.join(x.dropna().astype(str)),
axis=1)
country_df
국가 ID0 ID1 ID2 ID3 ID4 나머지국가
0 대한민국,미국,호주,영국 대한민국 미국 호주 영국 None 미국,호주,영국
1 대한민국,일본,중국 대한민국 일본 중국 None None 일본,중국
2 대한민국,베트남 대한민국 베트남 None None None 베트남
3 대한민국,필리핀 대한민국 필리핀 None None None 필리핀
4 대한민국,독일,체코,러시아,영국 대한민국 독일 체코 러시아 영국 독일,체코,러시아,영국
### 순서에 관계없이, 특정 컬럼을 지정해서, 하나의 컬럼으로 만들기
### 컬럼 인덱스 1번, 2번, 그리고 4번 이상의 모든 컬럼을 선택한다.
country_df['나머지국가'] = country_df[country_df.columns[[1] + [2] + list(range(4, len(country_df.columns)))]].apply(
lambda x : ','.join(x.dropna().astype(str)),
axis=1)
country_df
국가 ID0 ID1 ID2 ID3 ID4 나머지국가
0 대한민국,미국,호주,영국 대한민국 미국 호주 영국 None 대한민국,미국,영국
1 대한민국,일본,중국 대한민국 일본 중국 None None 대한민국,일본
2 대한민국,베트남 대한민국 베트남 None None None 대한민국,베트남
3 대한민국,필리핀 대한민국 필리핀 None None None 대한민국,필리핀
4 대한민국,독일,체코,러시아,영국 대한민국 독일 체코 러시아 영국 대한민국,독일,러시아,영국
country_df[['ID0','나머지국가']]
ID0 나머지국가
0 대한민국 미국,호주,영국
1 대한민국 일본,중국
2 대한민국 베트남
3 대한민국 필리핀
4 대한민국 독일,체코,러시아,영국
4. 로우 단위로 split하는 예시_1
특정 컬럼을 고정시키고,
다른 컬럼의 문자열 내부의 구분자를 이용하여
로우 단위로 데이터프레임을 split한다.
df = pd.DataFrame({"order_id":[1,3,7],"order_date":["20/5/2018","22/5/2018","23/5/2018"], "package":["p1,p2,p3","p4","p5,p6"],"package_code":["#111,#222,#333","#444","#555,#666"]})
df
order_id order_date package package_code
0 1 20/5/2018 p1,p2,p3 #111,#222,#333
1 3 22/5/2018 p4 #444
2 7 23/5/2018 p5,p6 #555,#666
df = (df.set_index(['order_id', 'order_date'])
.apply(lambda x: x.str.split(',').explode())
.reset_index())
df
order_id order_date package package_code
0 1 20/5/2018 p1 #111
1 1 20/5/2018 p2 #222
2 1 20/5/2018 p3 #333
3 3 22/5/2018 p4 #444
4 7 23/5/2018 p5 #555
5 7 23/5/2018 p6 #666
5. 로우 단위로 split하는 예시_2
특정 컬럼 하나에 대하여 로우 단위로 split하는 방법
괄호()안에 지정하거나 변경할 변수가 많아서,
사용시에 유의해야 한다.
여기서는 데이터프레임명(df)과 컬럼명(package) 지정할 때,
유의하면 된다.
df = pd.DataFrame({"order_id":[1,3,7],"order_date":["20/5/2018","22/5/2018","23/5/2018"], "package":["p1,p2,p3","p4","p5,p6"],"package_code":["#111,#222,#333","#444","#555,#666"]})
df
order_id order_date package package_code
0 1 20/5/2018 p1,p2,p3 #111,#222,#333
1 3 22/5/2018 p4 #444
2 7 23/5/2018 p5,p6 #555,#666
df = \
(df.set_index(df.columns.drop('package',1).tolist())
.package.str.split(',', expand=True)
.stack()
.reset_index()
.rename(columns={0:'package'})
.loc[:, df.columns]
)
df
order_id order_date package package_code
0 1 20/5/2018 p1 #111,#222,#333
1 1 20/5/2018 p2 #111,#222,#333
2 1 20/5/2018 p3 #111,#222,#333
3 3 22/5/2018 p4 #444
4 7 23/5/2018 p5 #555,#666
5 7 23/5/2018 p6 #555,#666
6. 복잡한 데이터프레임 split and concat 예시
df = pd.DataFrame({"ID":[6,6,6,7,7,8,8],"order_date":["21/05/2016","21/01/2014","02/04/2013","05/06/2014","12/08/2014","18/04/2012","21/03/2012"], "data":["A: 7, B: 8, C: 5, D: 5, A: 8","B: 5, C: 5, D: 7","A: 4, D:7","C: 25","D: 20","A: 2, B: 3, C: 3, E: 5, B: 4","F: 6, B: 4, F: 5, D: 6, B: 4 "]})
df
ID order_date data
0 6 21/05/2016 A: 7, B: 8, C: 5, D: 5, A: 8
1 6 21/01/2014 B: 5, C: 5, D: 7
2 6 02/04/2013 A: 4, D:7
3 7 05/06/2014 C: 25
4 7 12/08/2014 D: 20
5 8 18/04/2012 A: 2, B: 3, C: 3, E: 5, B: 4
6 8 21/03/2012 F: 6, B: 4, F: 5, D: 6, B: 4
import re
from collections import defaultdict
def str_to_dict(str1):
d = defaultdict(int)
for k, v in zip(re.findall('[A-Z]', str1), re.findall('\d+', str1)):
d[k] += int(v)
return d
pd.concat([df, df['data'].apply(str_to_dict).apply(pd.Series).fillna(0).astype(int)], axis=1)
ID order_date data A B C D E F
0 6 21/05/2016 A: 7, B: 8, C: 5, D: 5, A: 8 15 8 5 5 0 0
1 6 21/01/2014 B: 5, C: 5, D: 7 0 5 5 7 0 0
2 6 02/04/2013 A: 4, D:7 4 0 0 7 0 0
3 7 05/06/2014 C: 25 0 0 25 0 0 0
4 7 12/08/2014 D: 20 0 0 0 20 0 0
5 8 18/04/2012 A: 2, B: 3, C: 3, E: 5, B: 4 2 7 3 0 5 0
6 8 21/03/2012 F: 6, B: 4, F: 5, D: 6, B: 4 0 8 0 6 0 11
### reverse
df = pd.DataFrame([
[6, "a: 1, b: 2"],
[6, "a: 1, b: 2"],
[6, "a: 1, b: 2"],
[6, "a: 1, b: 2"],
], columns=['ID', 'dictionary'])
def str2dict(s):
split = s.strip().split(',')
d = {}
for pair in split:
k, v = [_.strip() for _ in pair.split(':')]
d[k] = v
return d
df.dictionary.apply(str2dict).apply(pd.Series)
a b
0 1 2
1 1 2
2 1 2
3 1 2
pd.concat([df, df.dictionary.apply(str2dict).apply(pd.Series)], axis=1)
ID dictionary a b
0 6 a: 1, b: 2 1 2
1 6 a: 1, b: 2 1 2
2 6 a: 1, b: 2 1 2
3 6 a: 1, b: 2 1 2
Reference
2. https://thats-it-code.com/pandas/how-to-split-one-column-to-multiple-columns/
3. https://suy379.tistory.com/126
6.https://stackoverflow.com/questions/50731229/split-cell-into-multiple-rows-in-pandas-dataframe
'Pandas' 카테고리의 다른 글
[Pandas] merge : 세 개 이상의, 여러 개의 데이터 프레임을 병합하는 방법 (0) | 2023.02.14 |
---|---|
[Pandas] 연속인 조건에서만 누적합(cumsum) 연산 (0) | 2022.12.16 |