2.5. 데이터프레임의 결합#
데이터를 이용하여 분석을 하는 경우 사용할 자료가 두 개 이상이 경우는 매우 흔한 일이다. 실제로 데이터 분석에서 하나의 자료만 가지고 수행하는 일은 매우 드물다. 이 절에서는 여러 개의 자료를 사용하는 경우 두 개의 자료를 서로 결합하여 새로운 자료를 만드는 것을 실습한다. 살펴 볼 내용은 다음과 같다.
데이터의 결합
식별자의 불일치
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
간단한 예제#
두 개의 데이터프레임 df1 과 df2 가 다음과 같이 주어졌다고 하자.
df1 = pd.DataFrame({
"name" : ["철수", "영이", "John"],
"age" : [23, 34, 19]
})
df1
| name | age | |
|---|---|---|
| 0 | 철수 | 23 |
| 1 | 영이 | 34 |
| 2 | John | 19 |
df2 = pd.DataFrame({
"name" : ["철수", "영이", "John"],
"sex" : ["M", "F", "M"]
})
df2
| name | sex | |
|---|---|---|
| 0 | 철수 | M |
| 1 | 영이 | F |
| 2 | John | M |
데이터프레임 df1 과 df2 에는 같은 이름을 가지는 열 name 이 있다. 우리는 두 개의 데이터프레임을 합쳐서 나이(age)와 성(sex) 이 모두 포함된 새로운 데이터프레임을 만들려고 한다.
이렇게 공통으로 포함된 열의 정보를 이용하여 두 개의 데이터프레임을 결합하려면 pandas 라이브러리의 merge() 함수 를 이용한다.
merge()함수의 첫 번째(왼쪽)와 두 번째 인자(오른쪽)에는 결합할 데이터프레임의 이름을 넣어준다.앞에
pd.를 붙여서pd.merge()로 사용하는 것은 함수merge()가 pandas 라이브러리에 있다는 것을 알려준다.선택문
on=에 두 데이터프레임에 결합의 기준이 되는 열이름을 문자열로 지정해준다. 결합의 기준으로 사용되는 열이름은 두 개의 데이터프레임에 모두 존재해야 한다.자료의 결합에 사용되는 공통으로 포함된 열의 내용을 식별자(key, identifier,..) 라고 부른다. 이 예제에서 식별자는 사람의 이름이다.
다음 코드의 결과를 먼저 보자.
pd.merge(df1, df2, on="name")
| name | age | sex | |
|---|---|---|---|
| 0 | 철수 | 23 | M |
| 1 | 영이 | 34 | F |
| 2 | John | 19 | M |
두 개의 데이터프레임이 지정된 열 name 에 의하여 결합되어 나이(age)와 성(sex)이 같이 나타나게 된다.
식별자의 불일치#
만약 두 개의 데이터프레임에 있는 식별자에 포함된 자료가 다르면 어떻게 될까?
다음과 같이 John 의 자료가 빠져 있는 데이터프레임 df3을 df1 과 결합해 보자.
df3 = pd.DataFrame({
"name" : ["철수", "영이"],
"weight" : [55, 44]
})
df3
| name | weight | |
|---|---|---|
| 0 | 철수 | 55 |
| 1 | 영이 | 44 |
pd.merge(df1, df3, on="name")
| name | age | weight | |
|---|---|---|---|
| 0 | 철수 | 23 | 55 |
| 1 | 영이 | 34 | 44 |
위의 결과에서 John 의 자료가 사라져 버렸다. 물론 몸무게 값이 없는 John 의 자료가 필요없을 수도 있지만 많은 경우 자료를 유지해야 한다.
이렇게 식별자의 항목이 다른 경우, 결합의 기준이 되는 식별자를 데이터프레임의 위치로 지정할 수 있다. 위에서 함수 merge()를 설명할 때 사용되는 데이터프레임의 위치에 따라서 왼쪽 (첫 번째 인자) 과 오른쪽 (두 번째 인자)으로 나타냈다.
pd.merge(left_df, right_df, on="name", how="inner")
how='left': 식별자는 왼쪽 데이터프레임에만 있는 것으로 선택how='right': 식별자는 오른쪽 데이터프레임에만 있는 것으로 선택how='inner': 식별자는 두 데이터프레임에 공통인 것으로 선택how='outer': 식별자는 두 데이터프레임에 나타난 모든 것으로 선택
식별자를 선택하는 선택명령문 how= 을 지정하지 않으면 자동으로 how='inner' 이 지정된다.

이제 결합시 기준이 되는 식별자가 왼쪽에 있는 데이터프레임 df1 에 있다는 것을 선택명령문 how='left' 로 알려주자.
pd.merge(df1, df3, on="name", how='left')
| name | age | weight | |
|---|---|---|---|
| 0 | 철수 | 23 | 55.0 |
| 1 | 영이 | 34 | 44.0 |
| 2 | John | 19 | NaN |
이제 John 의 자료가 나타나고 John 의 키는 결측값(NaN) 으로 표시된다.
만약 두 개의 식별자에 서로 다른 내용이 나타나면 어떻게 될까?
이제 새로운 사람 흥민의 자료를 가진 데이터프레임 df4를 df1 과 결합하는 예를 살펴보자. 아래 코드에서 선택명령문 how= 에 지정된 문자열에 따라서 결합의 결과가 어떻게 다른지 보자.
df4 = pd.DataFrame({
"name" : ["철수", "영이", "흥민"],
"height" : [167, 175, 183]
})
df4
| name | height | |
|---|---|---|
| 0 | 철수 | 167 |
| 1 | 영이 | 175 |
| 2 | 흥민 | 183 |
pd.merge(df1, df4, on="name", how='left') # 식별자는 왼쪽 데이터프레임에만 있는 것으로
| name | age | height | |
|---|---|---|---|
| 0 | 철수 | 23 | 167.0 |
| 1 | 영이 | 34 | 175.0 |
| 2 | John | 19 | NaN |
pd.merge(df1, df4, on="name", how='right') # 식별자는 오른쪽 데이터프레임만 있는 것으로
| name | age | height | |
|---|---|---|---|
| 0 | 철수 | 23.0 | 167 |
| 1 | 영이 | 34.0 | 175 |
| 2 | 흥민 | NaN | 183 |
pd.merge(df1, df4, on="name", how='inner') # 식별자는 두 데이터프레임에 공통인 것
| name | age | height | |
|---|---|---|---|
| 0 | 철수 | 23 | 167 |
| 1 | 영이 | 34 | 175 |
pd.merge(df1, df4, on="name", how='outer') # 식별자는 두 데이터프레임의 모든 것
| name | age | height | |
|---|---|---|---|
| 0 | 철수 | 23.0 | 167.0 |
| 1 | 영이 | 34.0 | 175.0 |
| 2 | John | 19.0 | NaN |
| 3 | 흥민 | NaN | 183.0 |
화재출동 데이터와 화재원인 데이터의 결합#
이번에는 화재출동 데이터 (fire_calling_summary.csv)와 화재원인 데이터 (fire_reason_summary.csv) 을 결합하는 작업을 해보려고 한다. 2017년부터 2021년의 5년간 서울시 5개 구별 (강동구, 강서구, 강남구, 강북구, 관악구) 정보가 있습니다.
df1 = pd.read_csv("https://uos-bigdata.github.io/lab_data/docs/assets/data_lab_fire/fire_calling_summary.csv", encoding = 'cp949')
df1
| 화재발생연도 | 시군구 | 사망자수 | 재산피해금액 | 출동횟수 | |
|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | 0.0 | 1565258 | 502 |
| 1 | 2017 | 강동구 | 0.0 | 418593 | 269 |
| 2 | 2017 | 강북구 | 0.0 | 339146 | 186 |
| 3 | 2017 | 강서구 | 3.0 | 706871 | 364 |
| 4 | 2017 | 관악구 | 3.0 | 654690 | 286 |
| 5 | 2018 | 강남구 | 0.0 | 1624983 | 436 |
| 6 | 2018 | 강동구 | 4.0 | 540625 | 324 |
| 7 | 2018 | 강북구 | 4.0 | 216838 | 203 |
| 8 | 2018 | 강서구 | 2.0 | 393401 | 383 |
| 9 | 2018 | 관악구 | 1.0 | 816562 | 337 |
| 10 | 2019 | 강남구 | 1.0 | 1677681 | 456 |
| 11 | 2019 | 강동구 | 1.0 | 533359 | 254 |
| 12 | 2019 | 강북구 | 1.0 | 217805 | 167 |
| 13 | 2019 | 강서구 | 0.0 | 666297 | 331 |
| 14 | 2019 | 관악구 | 3.0 | 654586 | 311 |
| 15 | 2020 | 강남구 | 1.0 | 1451556 | 387 |
| 16 | 2020 | 강동구 | 3.0 | 363839 | 221 |
| 17 | 2020 | 강북구 | 1.0 | 208380 | 186 |
| 18 | 2020 | 강서구 | 3.0 | 200966 | 212 |
| 19 | 2020 | 관악구 | 2.0 | 646149 | 219 |
| 20 | 2021 | 강남구 | 2.0 | 1354949 | 391 |
| 21 | 2021 | 강동구 | 1.0 | 346741 | 211 |
| 22 | 2021 | 강북구 | 5.0 | 410205 | 146 |
| 23 | 2021 | 강서구 | 2.0 | 559614 | 223 |
| 24 | 2021 | 관악구 | 2.0 | 562294 | 259 |
df2 = pd.read_csv("https://uos-bigdata.github.io/lab_data/docs/assets/data_lab_fire/fire_reason_summary.csv", encoding = 'cp949')
df2
| 연도 | 시군구명 | 작동기기 | 미상(발화원인) | 불꽃/ 불티 | 담뱃불/ 라이터불 | 마찰/ 전도/ 복사 | |
|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | 185 | 35 | 39 | 150 | 80 |
| 1 | 2017 | 강서구 | 144 | 26 | 22 | 88 | 80 |
| 2 | 2017 | 강동구 | 113 | 24 | 14 | 71 | 32 |
| 3 | 2017 | 강북구 | 100 | 11 | 9 | 42 | 23 |
| 4 | 2017 | 관악구 | 111 | 37 | 14 | 68 | 51 |
| 5 | 2018 | 강남구 | 216 | 32 | 24 | 131 | 29 |
| 6 | 2018 | 강서구 | 231 | 24 | 17 | 89 | 19 |
| 7 | 2018 | 강동구 | 174 | 14 | 15 | 87 | 32 |
| 8 | 2018 | 강북구 | 123 | 14 | 7 | 46 | 7 |
| 9 | 2018 | 관악구 | 209 | 30 | 21 | 71 | 3 |
| 10 | 2019 | 강남구 | 202 | 20 | 20 | 158 | 52 |
| 11 | 2019 | 강서구 | 147 | 22 | 19 | 81 | 38 |
| 12 | 2019 | 강동구 | 132 | 17 | 8 | 73 | 24 |
| 13 | 2019 | 강북구 | 100 | 15 | 6 | 38 | 5 |
| 14 | 2019 | 관악구 | 187 | 34 | 12 | 60 | 16 |
| 15 | 2020 | 강남구 | 167 | 21 | 21 | 151 | 23 |
| 16 | 2020 | 강서구 | 78 | 15 | 18 | 63 | 27 |
| 17 | 2020 | 강동구 | 132 | 12 | 9 | 49 | 14 |
| 18 | 2020 | 강북구 | 120 | 17 | 5 | 35 | 8 |
| 19 | 2020 | 관악구 | 116 | 19 | 14 | 62 | 7 |
| 20 | 2021 | 강남구 | 180 | 30 | 13 | 146 | 19 |
| 21 | 2021 | 강서구 | 113 | 17 | 13 | 55 | 19 |
| 22 | 2021 | 강동구 | 111 | 19 | 13 | 59 | 6 |
| 23 | 2021 | 강북구 | 76 | 12 | 5 | 38 | 12 |
| 24 | 2021 | 관악구 | 166 | 27 | 9 | 53 | 2 |
먼저 결합의 기준으로 삼을 열을 결정해야 한다. 우리의 데이터로는 연도와 시군구가 있다.
그런데 첫 번째 데이터에는 열 이름이 화재발생연도, 시군구라고 되어있고, 두 번째 데이터에는 연도와 시군구명으로 저장되어 있다. 데이터를 결합할 때에는 두 데이터의 기준 열 이름을 동일하게 맞춰주어야 한다. 따라서 첫 번째 데이터의 열 이름을 두 번째 데이터의 열 이름과 동일하게 바꿔주자.
df1.columns
Index(['화재발생연도', '시군구', '사망자수', '재산피해금액', '출동횟수'], dtype='object')
df1.columns = ['연도', '시군구명', '사망자수', '재산피해금액', '출동횟수']
df1
| 연도 | 시군구명 | 사망자수 | 재산피해금액 | 출동횟수 | |
|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | 0.0 | 1565258 | 502 |
| 1 | 2017 | 강동구 | 0.0 | 418593 | 269 |
| 2 | 2017 | 강북구 | 0.0 | 339146 | 186 |
| 3 | 2017 | 강서구 | 3.0 | 706871 | 364 |
| 4 | 2017 | 관악구 | 3.0 | 654690 | 286 |
| 5 | 2018 | 강남구 | 0.0 | 1624983 | 436 |
| 6 | 2018 | 강동구 | 4.0 | 540625 | 324 |
| 7 | 2018 | 강북구 | 4.0 | 216838 | 203 |
| 8 | 2018 | 강서구 | 2.0 | 393401 | 383 |
| 9 | 2018 | 관악구 | 1.0 | 816562 | 337 |
| 10 | 2019 | 강남구 | 1.0 | 1677681 | 456 |
| 11 | 2019 | 강동구 | 1.0 | 533359 | 254 |
| 12 | 2019 | 강북구 | 1.0 | 217805 | 167 |
| 13 | 2019 | 강서구 | 0.0 | 666297 | 331 |
| 14 | 2019 | 관악구 | 3.0 | 654586 | 311 |
| 15 | 2020 | 강남구 | 1.0 | 1451556 | 387 |
| 16 | 2020 | 강동구 | 3.0 | 363839 | 221 |
| 17 | 2020 | 강북구 | 1.0 | 208380 | 186 |
| 18 | 2020 | 강서구 | 3.0 | 200966 | 212 |
| 19 | 2020 | 관악구 | 2.0 | 646149 | 219 |
| 20 | 2021 | 강남구 | 2.0 | 1354949 | 391 |
| 21 | 2021 | 강동구 | 1.0 | 346741 | 211 |
| 22 | 2021 | 강북구 | 5.0 | 410205 | 146 |
| 23 | 2021 | 강서구 | 2.0 | 559614 | 223 |
| 24 | 2021 | 관악구 | 2.0 | 562294 | 259 |
데이터프레임 df1 과 df2 에는 같은 이름을 가지는 열 연도 와 시군구명 이 있다. 우리는 두 개의 데이터프레임을 합쳐 출동현황과 화재원인이 모두 포함된 새로운 데이터프레임을 만들 것이다.
pd.merge(df1, df2, on=["연도","시군구명"])
| 연도 | 시군구명 | 사망자수 | 재산피해금액 | 출동횟수 | 작동기기 | 미상(발화원인) | 불꽃/ 불티 | 담뱃불/ 라이터불 | 마찰/ 전도/ 복사 | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | 0.0 | 1565258 | 502 | 185 | 35 | 39 | 150 | 80 |
| 1 | 2017 | 강동구 | 0.0 | 418593 | 269 | 113 | 24 | 14 | 71 | 32 |
| 2 | 2017 | 강북구 | 0.0 | 339146 | 186 | 100 | 11 | 9 | 42 | 23 |
| 3 | 2017 | 강서구 | 3.0 | 706871 | 364 | 144 | 26 | 22 | 88 | 80 |
| 4 | 2017 | 관악구 | 3.0 | 654690 | 286 | 111 | 37 | 14 | 68 | 51 |
| 5 | 2018 | 강남구 | 0.0 | 1624983 | 436 | 216 | 32 | 24 | 131 | 29 |
| 6 | 2018 | 강동구 | 4.0 | 540625 | 324 | 174 | 14 | 15 | 87 | 32 |
| 7 | 2018 | 강북구 | 4.0 | 216838 | 203 | 123 | 14 | 7 | 46 | 7 |
| 8 | 2018 | 강서구 | 2.0 | 393401 | 383 | 231 | 24 | 17 | 89 | 19 |
| 9 | 2018 | 관악구 | 1.0 | 816562 | 337 | 209 | 30 | 21 | 71 | 3 |
| 10 | 2019 | 강남구 | 1.0 | 1677681 | 456 | 202 | 20 | 20 | 158 | 52 |
| 11 | 2019 | 강동구 | 1.0 | 533359 | 254 | 132 | 17 | 8 | 73 | 24 |
| 12 | 2019 | 강북구 | 1.0 | 217805 | 167 | 100 | 15 | 6 | 38 | 5 |
| 13 | 2019 | 강서구 | 0.0 | 666297 | 331 | 147 | 22 | 19 | 81 | 38 |
| 14 | 2019 | 관악구 | 3.0 | 654586 | 311 | 187 | 34 | 12 | 60 | 16 |
| 15 | 2020 | 강남구 | 1.0 | 1451556 | 387 | 167 | 21 | 21 | 151 | 23 |
| 16 | 2020 | 강동구 | 3.0 | 363839 | 221 | 132 | 12 | 9 | 49 | 14 |
| 17 | 2020 | 강북구 | 1.0 | 208380 | 186 | 120 | 17 | 5 | 35 | 8 |
| 18 | 2020 | 강서구 | 3.0 | 200966 | 212 | 78 | 15 | 18 | 63 | 27 |
| 19 | 2020 | 관악구 | 2.0 | 646149 | 219 | 116 | 19 | 14 | 62 | 7 |
| 20 | 2021 | 강남구 | 2.0 | 1354949 | 391 | 180 | 30 | 13 | 146 | 19 |
| 21 | 2021 | 강동구 | 1.0 | 346741 | 211 | 111 | 19 | 13 | 59 | 6 |
| 22 | 2021 | 강북구 | 5.0 | 410205 | 146 | 76 | 12 | 5 | 38 | 12 |
| 23 | 2021 | 강서구 | 2.0 | 559614 | 223 | 113 | 17 | 13 | 55 | 19 |
| 24 | 2021 | 관악구 | 2.0 | 562294 | 259 | 166 | 27 | 9 | 53 | 2 |
두 개의 데이터프레임이 지정된 열 연도와 시군구명 에 의하여 결합되어 나타나게 된다.
만약 두 개의 데이터프레임에 있는 식별자에 포함된 자료가 다르면 어떻게 될까? 다음 상황을 고려해보자.
2017년도의 자료가 빠져 있는 데이터프레임df1_no2017을 새로 만들자.df2과 결합해 보자.
df1_no2017 = df1[df1['연도'] != 2017]
df1_no2017
| 연도 | 시군구명 | 사망자수 | 재산피해금액 | 출동횟수 | |
|---|---|---|---|---|---|
| 5 | 2018 | 강남구 | 0.0 | 1624983 | 436 |
| 6 | 2018 | 강동구 | 4.0 | 540625 | 324 |
| 7 | 2018 | 강북구 | 4.0 | 216838 | 203 |
| 8 | 2018 | 강서구 | 2.0 | 393401 | 383 |
| 9 | 2018 | 관악구 | 1.0 | 816562 | 337 |
| 10 | 2019 | 강남구 | 1.0 | 1677681 | 456 |
| 11 | 2019 | 강동구 | 1.0 | 533359 | 254 |
| 12 | 2019 | 강북구 | 1.0 | 217805 | 167 |
| 13 | 2019 | 강서구 | 0.0 | 666297 | 331 |
| 14 | 2019 | 관악구 | 3.0 | 654586 | 311 |
| 15 | 2020 | 강남구 | 1.0 | 1451556 | 387 |
| 16 | 2020 | 강동구 | 3.0 | 363839 | 221 |
| 17 | 2020 | 강북구 | 1.0 | 208380 | 186 |
| 18 | 2020 | 강서구 | 3.0 | 200966 | 212 |
| 19 | 2020 | 관악구 | 2.0 | 646149 | 219 |
| 20 | 2021 | 강남구 | 2.0 | 1354949 | 391 |
| 21 | 2021 | 강동구 | 1.0 | 346741 | 211 |
| 22 | 2021 | 강북구 | 5.0 | 410205 | 146 |
| 23 | 2021 | 강서구 | 2.0 | 559614 | 223 |
| 24 | 2021 | 관악구 | 2.0 | 562294 | 259 |
pd.merge(df1_no2017, df2, on=["연도","시군구명"])
| 연도 | 시군구명 | 사망자수 | 재산피해금액 | 출동횟수 | 작동기기 | 미상(발화원인) | 불꽃/ 불티 | 담뱃불/ 라이터불 | 마찰/ 전도/ 복사 | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2018 | 강남구 | 0.0 | 1624983 | 436 | 216 | 32 | 24 | 131 | 29 |
| 1 | 2018 | 강동구 | 4.0 | 540625 | 324 | 174 | 14 | 15 | 87 | 32 |
| 2 | 2018 | 강북구 | 4.0 | 216838 | 203 | 123 | 14 | 7 | 46 | 7 |
| 3 | 2018 | 강서구 | 2.0 | 393401 | 383 | 231 | 24 | 17 | 89 | 19 |
| 4 | 2018 | 관악구 | 1.0 | 816562 | 337 | 209 | 30 | 21 | 71 | 3 |
| 5 | 2019 | 강남구 | 1.0 | 1677681 | 456 | 202 | 20 | 20 | 158 | 52 |
| 6 | 2019 | 강동구 | 1.0 | 533359 | 254 | 132 | 17 | 8 | 73 | 24 |
| 7 | 2019 | 강북구 | 1.0 | 217805 | 167 | 100 | 15 | 6 | 38 | 5 |
| 8 | 2019 | 강서구 | 0.0 | 666297 | 331 | 147 | 22 | 19 | 81 | 38 |
| 9 | 2019 | 관악구 | 3.0 | 654586 | 311 | 187 | 34 | 12 | 60 | 16 |
| 10 | 2020 | 강남구 | 1.0 | 1451556 | 387 | 167 | 21 | 21 | 151 | 23 |
| 11 | 2020 | 강동구 | 3.0 | 363839 | 221 | 132 | 12 | 9 | 49 | 14 |
| 12 | 2020 | 강북구 | 1.0 | 208380 | 186 | 120 | 17 | 5 | 35 | 8 |
| 13 | 2020 | 강서구 | 3.0 | 200966 | 212 | 78 | 15 | 18 | 63 | 27 |
| 14 | 2020 | 관악구 | 2.0 | 646149 | 219 | 116 | 19 | 14 | 62 | 7 |
| 15 | 2021 | 강남구 | 2.0 | 1354949 | 391 | 180 | 30 | 13 | 146 | 19 |
| 16 | 2021 | 강동구 | 1.0 | 346741 | 211 | 111 | 19 | 13 | 59 | 6 |
| 17 | 2021 | 강북구 | 5.0 | 410205 | 146 | 76 | 12 | 5 | 38 | 12 |
| 18 | 2021 | 강서구 | 2.0 | 559614 | 223 | 113 | 17 | 13 | 55 | 19 |
| 19 | 2021 | 관악구 | 2.0 | 562294 | 259 | 166 | 27 | 9 | 53 | 2 |
위의 결과에서 2017년도 의 자료가 사라져 버린 것을 확인할 수 있다. 물론 2017년도의 자료가 필요없을 수도 있지만 많은 경우 자료를 유지해야 한다.
이제 how 옵션을 바꾸어 결합 시 기준이 되는 식별자에 조건을 바꾸어보자. 먼저 결합시 기준이 되는 식별자가 오른쪽에 있는 데이터프레임 df1 에 있다는 것을 선택명령문 how='right' 로 알려주자.
pd.merge(df1_no2017, df2, on=["연도","시군구명"], how='right')
| 연도 | 시군구명 | 사망자수 | 재산피해금액 | 출동횟수 | 작동기기 | 미상(발화원인) | 불꽃/ 불티 | 담뱃불/ 라이터불 | 마찰/ 전도/ 복사 | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | NaN | NaN | NaN | 185 | 35 | 39 | 150 | 80 |
| 1 | 2017 | 강서구 | NaN | NaN | NaN | 144 | 26 | 22 | 88 | 80 |
| 2 | 2017 | 강동구 | NaN | NaN | NaN | 113 | 24 | 14 | 71 | 32 |
| 3 | 2017 | 강북구 | NaN | NaN | NaN | 100 | 11 | 9 | 42 | 23 |
| 4 | 2017 | 관악구 | NaN | NaN | NaN | 111 | 37 | 14 | 68 | 51 |
| 5 | 2018 | 강남구 | 0.0 | 1624983.0 | 436.0 | 216 | 32 | 24 | 131 | 29 |
| 6 | 2018 | 강서구 | 2.0 | 393401.0 | 383.0 | 231 | 24 | 17 | 89 | 19 |
| 7 | 2018 | 강동구 | 4.0 | 540625.0 | 324.0 | 174 | 14 | 15 | 87 | 32 |
| 8 | 2018 | 강북구 | 4.0 | 216838.0 | 203.0 | 123 | 14 | 7 | 46 | 7 |
| 9 | 2018 | 관악구 | 1.0 | 816562.0 | 337.0 | 209 | 30 | 21 | 71 | 3 |
| 10 | 2019 | 강남구 | 1.0 | 1677681.0 | 456.0 | 202 | 20 | 20 | 158 | 52 |
| 11 | 2019 | 강서구 | 0.0 | 666297.0 | 331.0 | 147 | 22 | 19 | 81 | 38 |
| 12 | 2019 | 강동구 | 1.0 | 533359.0 | 254.0 | 132 | 17 | 8 | 73 | 24 |
| 13 | 2019 | 강북구 | 1.0 | 217805.0 | 167.0 | 100 | 15 | 6 | 38 | 5 |
| 14 | 2019 | 관악구 | 3.0 | 654586.0 | 311.0 | 187 | 34 | 12 | 60 | 16 |
| 15 | 2020 | 강남구 | 1.0 | 1451556.0 | 387.0 | 167 | 21 | 21 | 151 | 23 |
| 16 | 2020 | 강서구 | 3.0 | 200966.0 | 212.0 | 78 | 15 | 18 | 63 | 27 |
| 17 | 2020 | 강동구 | 3.0 | 363839.0 | 221.0 | 132 | 12 | 9 | 49 | 14 |
| 18 | 2020 | 강북구 | 1.0 | 208380.0 | 186.0 | 120 | 17 | 5 | 35 | 8 |
| 19 | 2020 | 관악구 | 2.0 | 646149.0 | 219.0 | 116 | 19 | 14 | 62 | 7 |
| 20 | 2021 | 강남구 | 2.0 | 1354949.0 | 391.0 | 180 | 30 | 13 | 146 | 19 |
| 21 | 2021 | 강서구 | 2.0 | 559614.0 | 223.0 | 113 | 17 | 13 | 55 | 19 |
| 22 | 2021 | 강동구 | 1.0 | 346741.0 | 211.0 | 111 | 19 | 13 | 59 | 6 |
| 23 | 2021 | 강북구 | 5.0 | 410205.0 | 146.0 | 76 | 12 | 5 | 38 | 12 |
| 24 | 2021 | 관악구 | 2.0 | 562294.0 | 259.0 | 166 | 27 | 9 | 53 | 2 |
이제 2017년도 의 자료가 나타나고 2017년도 의 화재 원인 부분이 결측값(NaN) 으로 표시된다.
만약 두 개의 식별자에 서로 다른 내용이 나타나면 어떻게 될까? 다음과 같이 서로 다른 연도를 가진 데이터를 결합해보자.
2017~2020년도의 자료를 가진 데이터프레임df2_no2021를 새로 만든다.2018~2021년도의 자료를 가진 데이터프레임df1_no2017과 결합한다.
아래 코드에서 선택명령문 how= 에 지정된 문자열에 따라서 결합의 결과가 어떻게 다른지 확인한다.
df2_no2021 = df2[df2['연도'] != 2021]
df2_no2021
| 연도 | 시군구명 | 작동기기 | 미상(발화원인) | 불꽃/ 불티 | 담뱃불/ 라이터불 | 마찰/ 전도/ 복사 | |
|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | 185 | 35 | 39 | 150 | 80 |
| 1 | 2017 | 강서구 | 144 | 26 | 22 | 88 | 80 |
| 2 | 2017 | 강동구 | 113 | 24 | 14 | 71 | 32 |
| 3 | 2017 | 강북구 | 100 | 11 | 9 | 42 | 23 |
| 4 | 2017 | 관악구 | 111 | 37 | 14 | 68 | 51 |
| 5 | 2018 | 강남구 | 216 | 32 | 24 | 131 | 29 |
| 6 | 2018 | 강서구 | 231 | 24 | 17 | 89 | 19 |
| 7 | 2018 | 강동구 | 174 | 14 | 15 | 87 | 32 |
| 8 | 2018 | 강북구 | 123 | 14 | 7 | 46 | 7 |
| 9 | 2018 | 관악구 | 209 | 30 | 21 | 71 | 3 |
| 10 | 2019 | 강남구 | 202 | 20 | 20 | 158 | 52 |
| 11 | 2019 | 강서구 | 147 | 22 | 19 | 81 | 38 |
| 12 | 2019 | 강동구 | 132 | 17 | 8 | 73 | 24 |
| 13 | 2019 | 강북구 | 100 | 15 | 6 | 38 | 5 |
| 14 | 2019 | 관악구 | 187 | 34 | 12 | 60 | 16 |
| 15 | 2020 | 강남구 | 167 | 21 | 21 | 151 | 23 |
| 16 | 2020 | 강서구 | 78 | 15 | 18 | 63 | 27 |
| 17 | 2020 | 강동구 | 132 | 12 | 9 | 49 | 14 |
| 18 | 2020 | 강북구 | 120 | 17 | 5 | 35 | 8 |
| 19 | 2020 | 관악구 | 116 | 19 | 14 | 62 | 7 |
pd.merge(df1_no2017, df2_no2021, on=["연도","시군구명"], how='left') # 식별자는 왼쪽 데이터프레임에만 있는 것으로
| 연도 | 시군구명 | 사망자수 | 재산피해금액 | 출동횟수 | 작동기기 | 미상(발화원인) | 불꽃/ 불티 | 담뱃불/ 라이터불 | 마찰/ 전도/ 복사 | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2018 | 강남구 | 0.0 | 1624983 | 436 | 216.0 | 32.0 | 24.0 | 131.0 | 29.0 |
| 1 | 2018 | 강동구 | 4.0 | 540625 | 324 | 174.0 | 14.0 | 15.0 | 87.0 | 32.0 |
| 2 | 2018 | 강북구 | 4.0 | 216838 | 203 | 123.0 | 14.0 | 7.0 | 46.0 | 7.0 |
| 3 | 2018 | 강서구 | 2.0 | 393401 | 383 | 231.0 | 24.0 | 17.0 | 89.0 | 19.0 |
| 4 | 2018 | 관악구 | 1.0 | 816562 | 337 | 209.0 | 30.0 | 21.0 | 71.0 | 3.0 |
| 5 | 2019 | 강남구 | 1.0 | 1677681 | 456 | 202.0 | 20.0 | 20.0 | 158.0 | 52.0 |
| 6 | 2019 | 강동구 | 1.0 | 533359 | 254 | 132.0 | 17.0 | 8.0 | 73.0 | 24.0 |
| 7 | 2019 | 강북구 | 1.0 | 217805 | 167 | 100.0 | 15.0 | 6.0 | 38.0 | 5.0 |
| 8 | 2019 | 강서구 | 0.0 | 666297 | 331 | 147.0 | 22.0 | 19.0 | 81.0 | 38.0 |
| 9 | 2019 | 관악구 | 3.0 | 654586 | 311 | 187.0 | 34.0 | 12.0 | 60.0 | 16.0 |
| 10 | 2020 | 강남구 | 1.0 | 1451556 | 387 | 167.0 | 21.0 | 21.0 | 151.0 | 23.0 |
| 11 | 2020 | 강동구 | 3.0 | 363839 | 221 | 132.0 | 12.0 | 9.0 | 49.0 | 14.0 |
| 12 | 2020 | 강북구 | 1.0 | 208380 | 186 | 120.0 | 17.0 | 5.0 | 35.0 | 8.0 |
| 13 | 2020 | 강서구 | 3.0 | 200966 | 212 | 78.0 | 15.0 | 18.0 | 63.0 | 27.0 |
| 14 | 2020 | 관악구 | 2.0 | 646149 | 219 | 116.0 | 19.0 | 14.0 | 62.0 | 7.0 |
| 15 | 2021 | 강남구 | 2.0 | 1354949 | 391 | NaN | NaN | NaN | NaN | NaN |
| 16 | 2021 | 강동구 | 1.0 | 346741 | 211 | NaN | NaN | NaN | NaN | NaN |
| 17 | 2021 | 강북구 | 5.0 | 410205 | 146 | NaN | NaN | NaN | NaN | NaN |
| 18 | 2021 | 강서구 | 2.0 | 559614 | 223 | NaN | NaN | NaN | NaN | NaN |
| 19 | 2021 | 관악구 | 2.0 | 562294 | 259 | NaN | NaN | NaN | NaN | NaN |
pd.merge(df1_no2017, df2_no2021, on=["연도","시군구명"], how='right') # 식별자는 오른쪽 데이터프레임만 있는 것으로
| 연도 | 시군구명 | 사망자수 | 재산피해금액 | 출동횟수 | 작동기기 | 미상(발화원인) | 불꽃/ 불티 | 담뱃불/ 라이터불 | 마찰/ 전도/ 복사 | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | NaN | NaN | NaN | 185 | 35 | 39 | 150 | 80 |
| 1 | 2017 | 강서구 | NaN | NaN | NaN | 144 | 26 | 22 | 88 | 80 |
| 2 | 2017 | 강동구 | NaN | NaN | NaN | 113 | 24 | 14 | 71 | 32 |
| 3 | 2017 | 강북구 | NaN | NaN | NaN | 100 | 11 | 9 | 42 | 23 |
| 4 | 2017 | 관악구 | NaN | NaN | NaN | 111 | 37 | 14 | 68 | 51 |
| 5 | 2018 | 강남구 | 0.0 | 1624983.0 | 436.0 | 216 | 32 | 24 | 131 | 29 |
| 6 | 2018 | 강서구 | 2.0 | 393401.0 | 383.0 | 231 | 24 | 17 | 89 | 19 |
| 7 | 2018 | 강동구 | 4.0 | 540625.0 | 324.0 | 174 | 14 | 15 | 87 | 32 |
| 8 | 2018 | 강북구 | 4.0 | 216838.0 | 203.0 | 123 | 14 | 7 | 46 | 7 |
| 9 | 2018 | 관악구 | 1.0 | 816562.0 | 337.0 | 209 | 30 | 21 | 71 | 3 |
| 10 | 2019 | 강남구 | 1.0 | 1677681.0 | 456.0 | 202 | 20 | 20 | 158 | 52 |
| 11 | 2019 | 강서구 | 0.0 | 666297.0 | 331.0 | 147 | 22 | 19 | 81 | 38 |
| 12 | 2019 | 강동구 | 1.0 | 533359.0 | 254.0 | 132 | 17 | 8 | 73 | 24 |
| 13 | 2019 | 강북구 | 1.0 | 217805.0 | 167.0 | 100 | 15 | 6 | 38 | 5 |
| 14 | 2019 | 관악구 | 3.0 | 654586.0 | 311.0 | 187 | 34 | 12 | 60 | 16 |
| 15 | 2020 | 강남구 | 1.0 | 1451556.0 | 387.0 | 167 | 21 | 21 | 151 | 23 |
| 16 | 2020 | 강서구 | 3.0 | 200966.0 | 212.0 | 78 | 15 | 18 | 63 | 27 |
| 17 | 2020 | 강동구 | 3.0 | 363839.0 | 221.0 | 132 | 12 | 9 | 49 | 14 |
| 18 | 2020 | 강북구 | 1.0 | 208380.0 | 186.0 | 120 | 17 | 5 | 35 | 8 |
| 19 | 2020 | 관악구 | 2.0 | 646149.0 | 219.0 | 116 | 19 | 14 | 62 | 7 |
pd.merge(df1_no2017, df2_no2021, on=["연도","시군구명"], how='inner') # 식별자는 두 데이터프레임에 공통인 것
| 연도 | 시군구명 | 사망자수 | 재산피해금액 | 출동횟수 | 작동기기 | 미상(발화원인) | 불꽃/ 불티 | 담뱃불/ 라이터불 | 마찰/ 전도/ 복사 | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2018 | 강남구 | 0.0 | 1624983 | 436 | 216 | 32 | 24 | 131 | 29 |
| 1 | 2018 | 강동구 | 4.0 | 540625 | 324 | 174 | 14 | 15 | 87 | 32 |
| 2 | 2018 | 강북구 | 4.0 | 216838 | 203 | 123 | 14 | 7 | 46 | 7 |
| 3 | 2018 | 강서구 | 2.0 | 393401 | 383 | 231 | 24 | 17 | 89 | 19 |
| 4 | 2018 | 관악구 | 1.0 | 816562 | 337 | 209 | 30 | 21 | 71 | 3 |
| 5 | 2019 | 강남구 | 1.0 | 1677681 | 456 | 202 | 20 | 20 | 158 | 52 |
| 6 | 2019 | 강동구 | 1.0 | 533359 | 254 | 132 | 17 | 8 | 73 | 24 |
| 7 | 2019 | 강북구 | 1.0 | 217805 | 167 | 100 | 15 | 6 | 38 | 5 |
| 8 | 2019 | 강서구 | 0.0 | 666297 | 331 | 147 | 22 | 19 | 81 | 38 |
| 9 | 2019 | 관악구 | 3.0 | 654586 | 311 | 187 | 34 | 12 | 60 | 16 |
| 10 | 2020 | 강남구 | 1.0 | 1451556 | 387 | 167 | 21 | 21 | 151 | 23 |
| 11 | 2020 | 강동구 | 3.0 | 363839 | 221 | 132 | 12 | 9 | 49 | 14 |
| 12 | 2020 | 강북구 | 1.0 | 208380 | 186 | 120 | 17 | 5 | 35 | 8 |
| 13 | 2020 | 강서구 | 3.0 | 200966 | 212 | 78 | 15 | 18 | 63 | 27 |
| 14 | 2020 | 관악구 | 2.0 | 646149 | 219 | 116 | 19 | 14 | 62 | 7 |
pd.merge(df1_no2017, df2_no2021, on=["연도","시군구명"], how='outer') # 식별자는 두 데이터프레임의 모든 것
| 연도 | 시군구명 | 사망자수 | 재산피해금액 | 출동횟수 | 작동기기 | 미상(발화원인) | 불꽃/ 불티 | 담뱃불/ 라이터불 | 마찰/ 전도/ 복사 | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2018 | 강남구 | 0.0 | 1624983.0 | 436.0 | 216.0 | 32.0 | 24.0 | 131.0 | 29.0 |
| 1 | 2018 | 강동구 | 4.0 | 540625.0 | 324.0 | 174.0 | 14.0 | 15.0 | 87.0 | 32.0 |
| 2 | 2018 | 강북구 | 4.0 | 216838.0 | 203.0 | 123.0 | 14.0 | 7.0 | 46.0 | 7.0 |
| 3 | 2018 | 강서구 | 2.0 | 393401.0 | 383.0 | 231.0 | 24.0 | 17.0 | 89.0 | 19.0 |
| 4 | 2018 | 관악구 | 1.0 | 816562.0 | 337.0 | 209.0 | 30.0 | 21.0 | 71.0 | 3.0 |
| 5 | 2019 | 강남구 | 1.0 | 1677681.0 | 456.0 | 202.0 | 20.0 | 20.0 | 158.0 | 52.0 |
| 6 | 2019 | 강동구 | 1.0 | 533359.0 | 254.0 | 132.0 | 17.0 | 8.0 | 73.0 | 24.0 |
| 7 | 2019 | 강북구 | 1.0 | 217805.0 | 167.0 | 100.0 | 15.0 | 6.0 | 38.0 | 5.0 |
| 8 | 2019 | 강서구 | 0.0 | 666297.0 | 331.0 | 147.0 | 22.0 | 19.0 | 81.0 | 38.0 |
| 9 | 2019 | 관악구 | 3.0 | 654586.0 | 311.0 | 187.0 | 34.0 | 12.0 | 60.0 | 16.0 |
| 10 | 2020 | 강남구 | 1.0 | 1451556.0 | 387.0 | 167.0 | 21.0 | 21.0 | 151.0 | 23.0 |
| 11 | 2020 | 강동구 | 3.0 | 363839.0 | 221.0 | 132.0 | 12.0 | 9.0 | 49.0 | 14.0 |
| 12 | 2020 | 강북구 | 1.0 | 208380.0 | 186.0 | 120.0 | 17.0 | 5.0 | 35.0 | 8.0 |
| 13 | 2020 | 강서구 | 3.0 | 200966.0 | 212.0 | 78.0 | 15.0 | 18.0 | 63.0 | 27.0 |
| 14 | 2020 | 관악구 | 2.0 | 646149.0 | 219.0 | 116.0 | 19.0 | 14.0 | 62.0 | 7.0 |
| 15 | 2021 | 강남구 | 2.0 | 1354949.0 | 391.0 | NaN | NaN | NaN | NaN | NaN |
| 16 | 2021 | 강동구 | 1.0 | 346741.0 | 211.0 | NaN | NaN | NaN | NaN | NaN |
| 17 | 2021 | 강북구 | 5.0 | 410205.0 | 146.0 | NaN | NaN | NaN | NaN | NaN |
| 18 | 2021 | 강서구 | 2.0 | 559614.0 | 223.0 | NaN | NaN | NaN | NaN | NaN |
| 19 | 2021 | 관악구 | 2.0 | 562294.0 | 259.0 | NaN | NaN | NaN | NaN | NaN |
| 20 | 2017 | 강남구 | NaN | NaN | NaN | 185.0 | 35.0 | 39.0 | 150.0 | 80.0 |
| 21 | 2017 | 강서구 | NaN | NaN | NaN | 144.0 | 26.0 | 22.0 | 88.0 | 80.0 |
| 22 | 2017 | 강동구 | NaN | NaN | NaN | 113.0 | 24.0 | 14.0 | 71.0 | 32.0 |
| 23 | 2017 | 강북구 | NaN | NaN | NaN | 100.0 | 11.0 | 9.0 | 42.0 | 23.0 |
| 24 | 2017 | 관악구 | NaN | NaN | NaN | 111.0 | 37.0 | 14.0 | 68.0 | 51.0 |
요약#
두 개의 데이터프레임을 결합하는 경우 pandas 라이브러리의 함수 merge() 를 사용하며 식별자가 포함된 공통의 열은 on= 으로 지정한다. 결합의 방향을 how=로 지정한다.
함께해봅시다
화재출동 데이터 (
fire_call.csv)로 사망자수, 부상자수, 재산피해금액에 대한 연도와 시군구별 평균 데이터call_summ를 만들어주세요.화재원인 데이터 (
fire_reason.csv)로 작동기기, 불꽃/불티, 담뱃불/라이터불, 마찰/전도/복사에 대한 연도와 시군구별 평균을 데이터reason_summ를 만들어주세요.두 요약 데이터
call_summ와reason_summ를 연도와 시군구를 기준으로 결합하세요.
# import pandas as pd
# fire = pd.read_csv("https://uos-bigdata.github.io/lab_data/docs/assets/data_lab_fire/fire_calling.csv", encoding = 'cp949')
# reason = pd.read_csv("https://uos-bigdata.github.io/lab_data/docs/assets/data_lab_fire/fire_reason.csv")