-
[python] 파이썬 데이터 분석 - 데이터 병합, 그룹화 (pandas 활용)Dev/Python 2023. 1. 16. 02:24728x90
데이터 병합
- 공통키를 가진 두 개의 DataFrame을 하나로 만드는 것
- 방식 : Inner Join, Outer Join, Left Join, Right Join
Pandas의 merge(), join() 사용하여 병합 구현 가능
Pandas의 Index 기준으로 병합이 이루어지기도 한다.
Inner Join
- key 값이 A, B에 모두 존재해야 병합 가능
- 일치하는 key 값 없다면 결과 테이블에 포함되지 않는다.
Outer Join
- 공통된 값이 아닌 부분까지도 같이 병합
- Key 값이 한쪽에만 있어도 결합 가능
- 정보 없는 경우에는 결측 (NaN) 처리
- 양쪽 Dataframe의 모든 정보를 하나로 묶어서 가져온다.
Left Join
- 왼쪽 Dataframe (A)의 Key 값을 모두 포함
- 우측 Dataframe에 해당 정보가 없다면 결측 처리
데이터 연결
- 하나의 DataFrame에 다른 DataFrame 또는 Series를 연결하여 결과 집합 생성
- Pandas의 concat(df1, df2, axis,...) 이용하여 데이터 연결
- 축 axis 값에 따라 axis = 0 이면 행방향 연결, axis = 1 이면 열 방향 연결
활용 예시
- 데이터 병합 : 서로 다른 성격의 데이터를 병합하여 결과 데이터 프레임을 분석하여 사용
- 제품, 고객, 매출의 각 테이블 병합 후 분석
- 데이터 연결 : 여러 그룹으로 산재된 데이터를 하나로 취합할 경우
- 월별 데이터 -> 데이터 연결
2.3데이터합치기 DataFrame Merge
In [1]:import pandas as pd
Inner Join
In [2]:# [데이터 merge 실습용] 두개의 데이터프레임 생성 data1 = { '학번' : [1, 2, 3, 4], '이름' : ['아이유', '김연아', '홍길동', '강감찬'], '학과' : ['철학', '경영학', '컴퓨터', '통계학'] } data2 = { '학번' : [1, 2, 4, 5], '학년' : [2, 4, 3, 1], '학점' : [1.5, 2.0, 4.1, 3.8] } df1 = pd.DataFrame(data1) df2 = pd.DataFrame(data2) display(df1) display(df2)
학번 이름 학과 0 1 아이유 철학 1 2 김연아 경영학 2 3 홍길동 컴퓨터 3 4 강감찬 통계학 학번 학년 학점 0 1 2 1.5 1 2 4 2.0 2 4 3 4.1 3 5 1 3.8 In [4]:# inner join - 일치되는 것만 merge. inner_df = pd.merge(df1, df2, on='학번', how='inner') # 학번 컬럼 기준으로 inner 조인 수행 display(inner_df)
학번 이름 학과 학년 학점 0 1 아이유 철학 2 1.5 1 2 김연아 경영학 4 2.0 2 4 강감찬 통계학 3 4.1 Outer Join
In [7]:data1 = { '학번' : [1, 2, 3, 4], '이름' : ['아이유', '김연아', '홍길동', '강감찬'], '학과' : ['철학', '경영학', '컴퓨터', '통계학'] } data2 = { '학번' : [1, 2, 4, 5], '학년' : [2, 4, 3, 1], '학점' : [1.5, 2.0, 4.1, 3.8] } df1 = pd.DataFrame(data1) df2 = pd.DataFrame(data2)
In [9]:# outer join 사용 outer_df = pd.merge(df1,df2, on='학번', how = 'outer') display(outer_df)
학번 이름 학과 학년 학점 0 1 아이유 철학 2.0 1.5 1 2 김연아 경영학 4.0 2.0 2 3 홍길동 컴퓨터 NaN NaN 3 4 강감찬 통계학 3.0 4.1 4 5 NaN NaN 1.0 3.8 Left and Right Join
In [10]:left_df = pd.merge(df1, df2, on='학번', how='left') display(left_df) right_df = pd.merge(df1, df2, on='학번', how='right') display(right_df)
학번 이름 학과 학년 학점 0 1 아이유 철학 2.0 1.5 1 2 김연아 경영학 4.0 2.0 2 3 홍길동 컴퓨터 NaN NaN 3 4 강감찬 통계학 3.0 4.1 학번 이름 학과 학년 학점 0 1 아이유 철학 2 1.5 1 2 김연아 경영학 4 2.0 2 4 강감찬 통계학 3 4.1 3 5 NaN NaN 1 3.8 merge 응용 : 현실 데이터를 다를 때 생길만 한 경우
1) 같은 의미의 다른 컬럼 명을 병합할 떄
In [12]:data1 = { '학번' : [1, 2, 3, 4], '이름' : ['아이유', '김연아', '홍길동', '강감찬'], '학과' : ['철학', '경영학', '컴퓨터', '통계학'] } data2 = { '학생고유번호' : [1, 2, 4, 5], #학번 대신 학생고유번호로 기록 '학년' : [2, 4, 3, 1], '학점' : [1.5, 2.0, 4.1, 3.8] } df1 = pd.DataFrame(data1) df2 = pd.DataFrame(data2)
In [13]:display(df1) display(df2)
학번 이름 학과 0 1 아이유 철학 1 2 김연아 경영학 2 3 홍길동 컴퓨터 3 4 강감찬 통계학 학생고유번호 학년 학점 0 1 2 1.5 1 2 4 2.0 2 4 3 4.1 3 5 1 3.8 In [16]:merged_df = pd.merge(df1, df2, left_on='학번', right_on='학생고유번호', how='inner') display(merged_df)
학번 이름 학과 학생고유번호 학년 학점 0 1 아이유 철학 1 2 1.5 1 2 김연아 경영학 2 4 2.0 2 4 강감찬 통계학 4 3 4.1 In [19]:# 두개의 공통 키 중 하나를 삭제해야한다. merged_df.drop('학생고유번호', axis=1, inplace=True)
In [20]:merged_df
Out[20]:학번 이름 학과 학년 학점 0 1 아이유 철학 2 1.5 1 2 김연아 경영학 4 2.0 2 4 강감찬 통계학 3 4.1 2) 공유하는 컬럼이 없는 경우
In [30]:data1 = { '학번' : [1, 2, 3, 4], '이름' : ['아이유', '김연아', '홍길동', '강감찬'], '학과' : ['철학', '경영학', '컴퓨터', '통계학'] } data2 = { '학년' : [2, 4, 3, 1], '학점' : [1.5, 2.0, 4.1, 3.8] } df1 = pd.DataFrame(data1) df2 = pd.DataFrame(data2, index=[1, 2, 4, 5]) # 이상한 인덱스 부여 display(df1) display(df2)
학번 이름 학과 0 1 아이유 철학 1 2 김연아 경영학 2 3 홍길동 컴퓨터 3 4 강감찬 통계학 학년 학점 1 2 1.5 2 4 2.0 4 3 4.1 5 1 3.8 In [31]:# 양 데이터프레임의 인덱스로 병합 진행 merged_df = pd.merge(df1, df2, left_index=True, right_index = True, how='inner') display(merged_df) # 인덱스를 기준으로 inner조인 한다.
학번 이름 학과 학년 학점 1 2 김연아 경영학 2 1.5 2 3 홍길동 컴퓨터 4 2.0 In [32]:# 왼쪽은 학번을 기준으로 # 오른쪽은 인덱스를 기준으로 병합 merged_df2 = pd.merge(df1, df2, left_on='학번', right_index=True, how='inner') display(merged_df2)
학번 이름 학과 학년 학점 0 1 아이유 철학 2 1.5 1 2 김연아 경영학 4 2.0 3 4 강감찬 통계학 3 4.1 In [34]:# join 메소드를 사용 : 양쪽 데이터프레임의 인덱스를 기준으로 병합 df1.join(df2, how='inner') #index
Out[34]:학번 이름 학과 학년 학점 1 2 김연아 경영학 2 1.5 2 3 홍길동 컴퓨터 4 2.0 데이터 연결 pandas.concat
In [36]:import numpy as np import pandas as pd np.random.seed(1) # 예제를 위한 고정된 난수 생성
In [37]:# 3*2 정수로 구성된 매트릭스 생성 df1 = pd.DataFrame(np.random.randint(0, 9, (3,2)), #3*2 매트릭스 index=['a', 'b', 'c'], columns = ['one', 'two']) display(df1)
one two a 5 8 b 5 0 c 0 1 In [41]:# 2*2 정수로 구성된 두번째 매트릭스 생성 df2 = pd.DataFrame(np.random.randint(0, 9, (2,2)), index=['a', 'b'], columns = ['three', 'four']) display(df2)
three four a 7 0 b 6 7 In [44]:# df1 & df2 concat으로 연결 result_df = pd.concat([df1, df2], axis=1) # axis=1: 열방향으로 연결 display(result_df)
one two three four a 5 8 7.0 0.0 b 5 0 6.0 7.0 c 0 1 NaN NaN In [45]:# outer join으로도 concat과 같은 데이터프레임을 확인할 수 있음. merge_df = pd.merge(df1, df2, left_index = True, right_index = True, how = 'outer') display(merge_df)
one two three four a 5 8 7.0 0.0 b 5 0 6.0 7.0 c 0 1 NaN NaN In [47]:# 행방향 연결 : axis=0 result_df = pd.concat([df1, df2], axis=0) display(result_df)
one two three four a 5.0 8.0 NaN NaN b 5.0 0.0 NaN NaN c 0.0 1.0 NaN NaN a NaN NaN 7.0 0.0 b NaN NaN 6.0 7.0 In [49]:# 새로운 데이터 생성 data1 = { '학번' : [1, 2, 3, 4], '이름' : ['아이유', '김연아', '홍길동', '강감찬'], '학과' : ['철학', '경영학', '컴퓨터', '통계학'] } data2 = { '학번' : [5, 6, 7, 8], '이름' : ['김범수', '이을용', '이순신', '김한국'], '학과' : ['경제학', '국문학', '경영학', '경영학'] } df1 = pd.DataFrame(data1) df2 = pd.DataFrame(data2) display(df1) display(df2)
학번 이름 학과 0 1 아이유 철학 1 2 김연아 경영학 2 3 홍길동 컴퓨터 3 4 강감찬 통계학 학번 이름 학과 0 5 김범수 경제학 1 6 이을용 국문학 2 7 이순신 경영학 3 8 김한국 경영학 In [51]:# pandas concat 예시 concat_df = pd.concat([df1, df2], axis = 0) # 행방향 연결 concat_df.reset_index(drop = True, inplace = True) # drop 인수를 주면서, index 컬럼을 따로 빼지 않는다. display(concat_df)
학번 이름 학과 0 1 아이유 철학 1 2 김연아 경영학 2 3 홍길동 컴퓨터 3 4 강감찬 통계학 4 5 김범수 경제학 5 6 이을용 국문학 6 7 이순신 경영학 7 8 김한국 경영학
데이터 그룹화
- 특정 데이터 그룹의 특징에 관한 정보를 얻기 위함
- Pandas의 groupby() 이용, 특정 열, 열의 리스트, 또는 행 인덱스 기준으로 그룹화 진행
- 그룹별 집계함수 사용 가능
- Groupby 객체의 apply() 이용하여 내장함수 외 사용자 정의 함수 사용 가능
cf ) sort_values() 이용 Series, DataFrame 데이터 정렬 가능
2.4데이터그룹핑 데이터 그룹핑
groupby 함수
In [4]:import numpy as np import pandas as pd
In [5]:df = pd.DataFrame({ '학과' : ['수학', '화학', '수학', '화학', '수학'], '이름' : ['로버트', '앤드류', '유진', '제이슨', '제이크'], '학년' : [1, 2, 3, 2, 3], '학점' : [1.5, 2.7, 3.5, 1.9, 4.0] }) display(df)
학과 이름 학년 학점 0 수학 로버트 1 1.5 1 화학 앤드류 2 2.7 2 수학 유진 3 3.5 3 화학 제이슨 2 1.9 4 수학 제이크 3 4.0 In [6]:df_dept = df.groupby('학과') # 데이터프레임에 대해서 학과를 기준으로 그룹화를 실행.
In [7]:print(df_dept) # 데이터프레임의 GroupBy 객체가 반환된다.
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x00000278144BCE88>
In [8]:# 학과별 기술통계 출력 df_dept.describe()
Out[8]:학년 학점 count mean std min 25% 50% 75% max count mean std min 25% 50% 75% max 학과 수학 3.0 2.333333 1.154701 1.0 2.0 3.0 3.0 3.0 3.0 3.0 1.322876 1.5 2.5 3.5 3.75 4.0 화학 2.0 2.000000 0.000000 2.0 2.0 2.0 2.0 2.0 2.0 2.3 0.565685 1.9 2.1 2.3 2.50 2.7 In [9]:# 학과별 원소 개수 출력 df_dept.count()
Out[9]:이름 학년 학점 학과 수학 3 3 3 화학 2 2 2 1단계 그룹핑
In [10]:# Series에 대한 1단계 그룹핑 dept = df['학점'].groupby(df['학과']) # df['컬럼1개']의 경우 series로 반환 됨. print(dept)
<pandas.core.groupby.generic.SeriesGroupBy object at 0x0000027814551048>
In [11]:# 학과 평균 성적 출력 dept.mean()
Out[11]:학과 수학 3.0 화학 2.3 Name: 학점, dtype: float64
In [12]:# 학과 성적 표준편차 출력 dept.std()
Out[12]:학과 수학 1.322876 화학 0.565685 Name: 학점, dtype: float64
In [13]:# group별 크기 출력 group_size = dept.size() print(group_size)
학과 수학 3 화학 2 Name: 학점, dtype: int64
In [14]:# 수학과 인원의 데이터만 따로 출력 math = dept.get_group('수학') print(math) # 수학과 학생들의 성적만 나온다.
0 1.5 2 3.5 4 4.0 Name: 학점, dtype: float64
2단계 그룹핑
In [15]:# 2단계 그룹핑 dept = df.groupby([df['학과'], df['학년']]) # 학과와 학년으로 그룹화 진행 dept
Out[15]:<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000002781455F6C8>
In [16]:# 그룹별 기술 통계 정보 도출 dept.describe()
Out[16]:학점 count mean std min 25% 50% 75% max 학과 학년 수학 1 1.0 1.50 NaN 1.5 1.500 1.50 1.500 1.5 3 2.0 3.75 0.353553 3.5 3.625 3.75 3.875 4.0 화학 2 2.0 2.30 0.565685 1.9 2.100 2.30 2.500 2.7 In [17]:display(dept.mean()) # 그룹 평균값 도출
학점 학과 학년 수학 1 1.50 3 3.75 화학 2 2.30 In [18]:# 더 많은 데이터 df2 = pd.DataFrame({ '학과' : ['화학', '수학', '화학', '수학'], '이름' : ['앤디', '제니', '엘리스', '멜리샤'], '학년' : [1, 2, 3, 2], '학점' : [3, 4.2, 3.1, 4.5] }) # df1, df2 행방향 연결 concat_df = pd.concat([df, df2], axis=0) concat_df.reset_index(inplace=True, drop=True) display(concat_df)
학과 이름 학년 학점 0 수학 로버트 1 1.5 1 화학 앤드류 2 2.7 2 수학 유진 3 3.5 3 화학 제이슨 2 1.9 4 수학 제이크 3 4.0 5 화학 앤디 1 3.0 6 수학 제니 2 4.2 7 화학 엘리스 3 3.1 8 수학 멜리샤 2 4.5 In [19]:# 학과와 학년별로 그룹핑 dept_and_year = concat_df.groupby([concat_df['학과'], concat_df['학년']])
In [20]:# 학과 & 학년 별 기술 통계 정보 출력 dept_and_year.describe()
Out[20]:학점 count mean std min 25% 50% 75% max 학과 학년 수학 1 1.0 1.50 NaN 1.5 1.500 1.50 1.500 1.5 2 2.0 4.35 0.212132 4.2 4.275 4.35 4.425 4.5 3 2.0 3.75 0.353553 3.5 3.625 3.75 3.875 4.0 화학 1 1.0 3.00 NaN 3.0 3.000 3.00 3.000 3.0 2 2.0 2.30 0.565685 1.9 2.100 2.30 2.500 2.7 3 1.0 3.10 NaN 3.1 3.100 3.10 3.100 3.1 In [21]:# 그룹별 평균 출력 dept_and_year.mean()
Out[21]:학점 학과 학년 수학 1 1.50 2 4.35 3 3.75 화학 1 3.00 2 2.30 3 3.10 In [22]:# 2단계 그룹화 인덱스 확인 dept_and_year.mean().index # 튜플 형태의 인덱스를 확인할 수 있다.
Out[22]:MultiIndex([('수학', 1), ('수학', 2), ('수학', 3), ('화학', 1), ('화학', 2), ('화학', 3)], names=['학과', '학년'])
apply 함수
In [24]:# 학과별 우수 성적자 3명 출력 함수 def top3_dept_scorer(df): return df.sort_values(by='학점', ascending=False)[:3] #학점 상위 3명 리턴
In [25]:# 학과 그룹바이 객체 생성 dept = concat_df.groupby('학과')
In [27]:# apply와 top3_dept_scorer 함수 dept.apply(top3_dept_scorer)
Out[27]:학과 이름 학년 학점 학과 수학 8 수학 멜리샤 2 4.5 6 수학 제니 2 4.2 4 수학 제이크 3 4.0 화학 7 화학 엘리스 3 3.1 5 화학 앤디 1 3.0 1 화학 앤드류 2 2.7 In [29]:# 학과 최우수 성적 2명을 출력하는 함수 def top2_scorer(series): return series.sort_values(ascending=False)[:2]
In [30]:dept['학점'].apply(top2_scorer) # 멀티 인덱스인 경우 보기 힘들게 표시됨.
Out[30]:학과 수학 8 4.5 6 4.2 화학 7 3.1 5 3.0 Name: 학점, dtype: float64
In [31]:# 멀티인덱스의 경우 데이터 프레임으로 보면 정렬된 뷰를 볼 수 있다. pd.DataFrame(dept['학점'].apply(top2_scorer))
Out[31]:학점 학과 수학 8 4.5 6 4.2 화학 7 3.1 5 3.0 lambda 활용
In [32]:# 새로운 데이터 프레임 생성 df = pd.DataFrame({ 'key' : ['A', 'B', 'B', 'C', 'A', 'C', 'A', 'B', 'C', 'A'], 'data' : [1, 2, 2, 1, 3, 8, 2, 5, 3, 6] })
In [33]:# key별로 그룹화 진행 후 data 값의 크기 별로 오름차순 정렬 df.groupby('key').apply(lambda x: x.sort_values(by='data'))
Out[33]:key data key A 0 A 1 6 A 2 4 A 3 9 A 6 B 1 B 2 2 B 2 7 B 5 C 3 C 1 8 C 3 5 C 8 In [34]:# 위에서 apply 함수를 이용하여 진행한 학과별 성적 탑 3명 학생 출력을 lambda 식으로 진행 dept = concat_df.groupby('학과')
In [35]:dept.apply(lambda x: x.sort_values(by='학점', ascending=False)[:3])
Out[35]:학과 이름 학년 학점 학과 수학 8 수학 멜리샤 2 4.5 6 수학 제니 2 4.2 4 수학 제이크 3 4.0 화학 7 화학 엘리스 3 3.1 5 화학 앤디 1 3.0 1 화학 앤드류 2 2.7 groupby와 재귀 함수
In [37]:# 1차 그룹핑 재귀 for dept, group in concat_df.groupby(concat_df['학과']): print('학과: {}'.format(dept)) display(group)
학과: 수학
학과 이름 학년 학점 0 수학 로버트 1 1.5 2 수학 유진 3 3.5 4 수학 제이크 3 4.0 6 수학 제니 2 4.2 8 수학 멜리샤 2 4.5 학과: 화학
학과 이름 학년 학점 1 화학 앤드류 2 2.7 3 화학 제이슨 2 1.9 5 화학 앤디 1 3.0 7 화학 엘리스 3 3.1 In [38]:# 2차 그룹핑 재귀 for (dept, year), group in concat_df.groupby([concat_df['학과'], concat_df['학년']]): # 학과와 학년으로 그룹바이 진행 print('-'*25) print('학과: ', dept) print('학년: ', year) display(group)
------------------------- 학과: 수학 학년: 1
학과 이름 학년 학점 0 수학 로버트 1 1.5 ------------------------- 학과: 수학 학년: 2
학과 이름 학년 학점 6 수학 제니 2 4.2 8 수학 멜리샤 2 4.5 ------------------------- 학과: 수학 학년: 3
학과 이름 학년 학점 2 수학 유진 3 3.5 4 수학 제이크 3 4.0 ------------------------- 학과: 화학 학년: 1
학과 이름 학년 학점 5 화학 앤디 1 3.0 ------------------------- 학과: 화학 학년: 2
학과 이름 학년 학점 1 화학 앤드류 2 2.7 3 화학 제이슨 2 1.9 ------------------------- 학과: 화학 학년: 3
학과 이름 학년 학점 7 화학 엘리스 3 3.1 728x90반응형'Dev > Python' 카테고리의 다른 글
[python] 파이썬 데이터 분석 - 시계열 데이터 (pandas 활용, 시각화) (1) 2023.01.16 [python] 파이썬 데이터 분석 - 데이터 조작 (pandas, numpy 활용 - 데이터 조작, 변경) (0) 2023.01.16 [python] 파이썬 anaconda 환경 설정 명령어 (0) 2023.01.16 [Python] 파이썬 웹 크롤링 - Selenium 이용한 트위터 자동 로그인 매크로 봇 만들기(2) - 다중 계정 로그인 (2) 2022.12.23 [Python] 파이썬 웹 크롤링 - Selenium 이용한 트위터 자동 로그인 매크로 봇 만들기 (1) - 단일 계정 (0) 2022.12.22