2.3. 데이터프레임 실습 1: 정리와 요약#
앞서 파이썬에서 기본적인 자료의 입력과 데이터프레임의 생성, 정리, 요약에 대해 배우고 예제 데이터로 실습하였다. 이번 시간에는 실제 데이터로 지난 시간에 배운 내용을 실습해보자.
화재출동 데이터#
데이터는 2017년부터 2021년의 5년간 서울시 모든 구의 화재출동 데이터 (fire_calling_summary.csv)입니다.
1. 데이터 불러오기
pandas패키지의 read_csv함수를 사용하여 csv파일을 데이터프레임으로 불러오자.
import pandas as pd
df = pd.read_csv("https://uos-bigdata.github.io/lab_data/docs/assets/data_lab_fire/fire_calling.csv", encoding = 'cp949')
df
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | NaN | 11 | 1565258 | 502 | 129 | 120 |
| 1 | 2017 | 강동구 | NaN | 12 | 418593 | 269 | 63 | 73 |
| 2 | 2017 | 강북구 | NaN | 6 | 339146 | 186 | 51 | 41 |
| 3 | 2017 | 강서구 | 3.0 | 22 | 706871 | 364 | 89 | 81 |
| 4 | 2017 | 관악구 | 3.0 | 20 | 654690 | 286 | 82 | 69 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 120 | 2021 | 용산구 | NaN | 5 | 296793 | 176 | 47 | 36 |
| 121 | 2021 | 은평구 | 3.0 | 8 | 875722 | 160 | 57 | 42 |
| 122 | 2021 | 종로구 | NaN | 12 | 465499 | 192 | 48 | 54 |
| 123 | 2021 | 중구 | NaN | 16 | 2780374 | 171 | 41 | 49 |
| 124 | 2021 | 중랑구 | 1.0 | 12 | 345257 | 213 | 63 | 59 |
125 rows × 8 columns
2. 데이터 확인
데이터가 한 페이지에 담기지 않아 약간 잘리게 나온다. 데이터를 조금씩 확인하고 싶다면 head 혹은 tail 메소드를 사용해보자.
데이터의 가장 처음 5개를 보고 싶으면 df.head(5), 데이터의 가장 마지막 5개를 보고 싶다면 df.tail(5) 로 입력해주면 된다.
df.head(5)
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | NaN | 11 | 1565258 | 502 | 129 | 120 |
| 1 | 2017 | 강동구 | NaN | 12 | 418593 | 269 | 63 | 73 |
| 2 | 2017 | 강북구 | NaN | 6 | 339146 | 186 | 51 | 41 |
| 3 | 2017 | 강서구 | 3.0 | 22 | 706871 | 364 | 89 | 81 |
| 4 | 2017 | 관악구 | 3.0 | 20 | 654690 | 286 | 82 | 69 |
df.tail(5)
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 120 | 2021 | 용산구 | NaN | 5 | 296793 | 176 | 47 | 36 |
| 121 | 2021 | 은평구 | 3.0 | 8 | 875722 | 160 | 57 | 42 |
| 122 | 2021 | 종로구 | NaN | 12 | 465499 | 192 | 48 | 54 |
| 123 | 2021 | 중구 | NaN | 16 | 2780374 | 171 | 41 | 49 |
| 124 | 2021 | 중랑구 | 1.0 | 12 | 345257 | 213 | 63 | 59 |
새로운 문제가 생겼다.
NaN은 ‘Not a Number’을 의미한다. 즉, 숫자가 아니라는 것이다. 연산의 결과가 숫자로 표현될 수 없거나 값이 부재하는 경우(결측값, missing data)에 나타나는 표현이다.
이 경우 사망자수가 0인 값이라고 인식한 후 NaN을 대체한다.
df = df.fillna(0)
df
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | 0.0 | 11 | 1565258 | 502 | 129 | 120 |
| 1 | 2017 | 강동구 | 0.0 | 12 | 418593 | 269 | 63 | 73 |
| 2 | 2017 | 강북구 | 0.0 | 6 | 339146 | 186 | 51 | 41 |
| 3 | 2017 | 강서구 | 3.0 | 22 | 706871 | 364 | 89 | 81 |
| 4 | 2017 | 관악구 | 3.0 | 20 | 654690 | 286 | 82 | 69 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 120 | 2021 | 용산구 | 0.0 | 5 | 296793 | 176 | 47 | 36 |
| 121 | 2021 | 은평구 | 3.0 | 8 | 875722 | 160 | 57 | 42 |
| 122 | 2021 | 종로구 | 0.0 | 12 | 465499 | 192 | 48 | 54 |
| 123 | 2021 | 중구 | 0.0 | 16 | 2780374 | 171 | 41 | 49 |
| 124 | 2021 | 중랑구 | 1.0 | 12 | 345257 | 213 | 63 | 59 |
125 rows × 8 columns
데이터를 연도별, 시군구별, 재산피해금액을 기준으로 각각 정렬시켜보자. 정렬을 할 때에는 sort_values()메소드 사용한다.
df.sort_values(by = '화재발생연도')
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | 0.0 | 11 | 1565258 | 502 | 129 | 120 |
| 1 | 2017 | 강동구 | 0.0 | 12 | 418593 | 269 | 63 | 73 |
| 2 | 2017 | 강북구 | 0.0 | 6 | 339146 | 186 | 51 | 41 |
| 19 | 2017 | 영등포구 | 1.0 | 16 | 1093594 | 239 | 65 | 64 |
| 20 | 2017 | 용산구 | 0.0 | 6 | 262910 | 167 | 37 | 45 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 114 | 2021 | 서초구 | 0.0 | 9 | 549807 | 231 | 69 | 51 |
| 107 | 2021 | 금천구 | 2.0 | 8 | 825255 | 118 | 37 | 28 |
| 108 | 2021 | 노원구 | 1.0 | 12 | 432605 | 173 | 48 | 49 |
| 116 | 2021 | 성북구 | 4.0 | 46 | 493231 | 168 | 56 | 37 |
| 115 | 2021 | 성동구 | 0.0 | 5 | 458412 | 191 | 48 | 54 |
125 rows × 8 columns
df.sort_values(by = '시군구')
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | 0.0 | 11 | 1565258 | 502 | 129 | 120 |
| 100 | 2021 | 강남구 | 2.0 | 15 | 1354949 | 391 | 112 | 91 |
| 25 | 2018 | 강남구 | 0.0 | 23 | 1624983 | 436 | 134 | 111 |
| 75 | 2020 | 강남구 | 1.0 | 18 | 1451556 | 387 | 100 | 98 |
| 50 | 2019 | 강남구 | 1.0 | 23 | 1677681 | 456 | 120 | 125 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 74 | 2019 | 중랑구 | 1.0 | 9 | 322650 | 210 | 54 | 49 |
| 49 | 2018 | 중랑구 | 2.0 | 8 | 201421 | 254 | 72 | 55 |
| 24 | 2017 | 중랑구 | 2.0 | 5 | 332366 | 196 | 53 | 38 |
| 99 | 2020 | 중랑구 | 2.0 | 12 | 229566 | 225 | 54 | 57 |
| 124 | 2021 | 중랑구 | 1.0 | 12 | 345257 | 213 | 63 | 59 |
125 rows × 8 columns
df.sort_values(by = '재산피해금액')
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 61 | 2019 | 동작구 | 2.0 | 10 | 179243 | 208 | 52 | 53 |
| 58 | 2019 | 노원구 | 0.0 | 6 | 185642 | 203 | 49 | 46 |
| 86 | 2020 | 동작구 | 0.0 | 7 | 194251 | 151 | 39 | 37 |
| 78 | 2020 | 강서구 | 3.0 | 5 | 200966 | 212 | 42 | 53 |
| 49 | 2018 | 중랑구 | 2.0 | 8 | 201421 | 254 | 72 | 55 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 123 | 2021 | 중구 | 0.0 | 16 | 2780374 | 171 | 41 | 49 |
| 69 | 2019 | 영등포구 | 1.0 | 48 | 3099954 | 265 | 64 | 63 |
| 85 | 2020 | 동대문구 | 6.0 | 17 | 3392558 | 152 | 43 | 34 |
| 38 | 2018 | 서대문구 | 4.0 | 9 | 7877501 | 229 | 50 | 69 |
| 73 | 2019 | 중구 | 3.0 | 17 | 74077097 | 213 | 51 | 39 |
125 rows × 8 columns
재산피해금액이 가장 큰 순으로 확인하고 싶으면 내림차순 정렬을 위한 선택문 ascending=False을 지정해주면 된다.
df.sort_values(by = '재산피해금액', ascending=False)
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 73 | 2019 | 중구 | 3.0 | 17 | 74077097 | 213 | 51 | 39 |
| 38 | 2018 | 서대문구 | 4.0 | 9 | 7877501 | 229 | 50 | 69 |
| 85 | 2020 | 동대문구 | 6.0 | 17 | 3392558 | 152 | 43 | 34 |
| 69 | 2019 | 영등포구 | 1.0 | 48 | 3099954 | 265 | 64 | 63 |
| 123 | 2021 | 중구 | 0.0 | 16 | 2780374 | 171 | 41 | 49 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 49 | 2018 | 중랑구 | 2.0 | 8 | 201421 | 254 | 72 | 55 |
| 78 | 2020 | 강서구 | 3.0 | 5 | 200966 | 212 | 42 | 53 |
| 86 | 2020 | 동작구 | 0.0 | 7 | 194251 | 151 | 39 | 37 |
| 58 | 2019 | 노원구 | 0.0 | 6 | 185642 | 203 | 49 | 46 |
| 61 | 2019 | 동작구 | 2.0 | 10 | 179243 | 208 | 52 | 53 |
125 rows × 8 columns
정렬 기준은 두 개 이상으로 줄 수도 있다. 시군구, 연도 그리고 연도, 시군구로 각각 정렬시켜보고 두 결과의 차이를 확인해보자.
df.sort_values(by = ['시군구', '화재발생연도'])
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | 0.0 | 11 | 1565258 | 502 | 129 | 120 |
| 25 | 2018 | 강남구 | 0.0 | 23 | 1624983 | 436 | 134 | 111 |
| 50 | 2019 | 강남구 | 1.0 | 23 | 1677681 | 456 | 120 | 125 |
| 75 | 2020 | 강남구 | 1.0 | 18 | 1451556 | 387 | 100 | 98 |
| 100 | 2021 | 강남구 | 2.0 | 15 | 1354949 | 391 | 112 | 91 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 24 | 2017 | 중랑구 | 2.0 | 5 | 332366 | 196 | 53 | 38 |
| 49 | 2018 | 중랑구 | 2.0 | 8 | 201421 | 254 | 72 | 55 |
| 74 | 2019 | 중랑구 | 1.0 | 9 | 322650 | 210 | 54 | 49 |
| 99 | 2020 | 중랑구 | 2.0 | 12 | 229566 | 225 | 54 | 57 |
| 124 | 2021 | 중랑구 | 1.0 | 12 | 345257 | 213 | 63 | 59 |
125 rows × 8 columns
df.sort_values(by = ['화재발생연도', '시군구'])
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | 0.0 | 11 | 1565258 | 502 | 129 | 120 |
| 1 | 2017 | 강동구 | 0.0 | 12 | 418593 | 269 | 63 | 73 |
| 2 | 2017 | 강북구 | 0.0 | 6 | 339146 | 186 | 51 | 41 |
| 3 | 2017 | 강서구 | 3.0 | 22 | 706871 | 364 | 89 | 81 |
| 4 | 2017 | 관악구 | 3.0 | 20 | 654690 | 286 | 82 | 69 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 120 | 2021 | 용산구 | 0.0 | 5 | 296793 | 176 | 47 | 36 |
| 121 | 2021 | 은평구 | 3.0 | 8 | 875722 | 160 | 57 | 42 |
| 122 | 2021 | 종로구 | 0.0 | 12 | 465499 | 192 | 48 | 54 |
| 123 | 2021 | 중구 | 0.0 | 16 | 2780374 | 171 | 41 | 49 |
| 124 | 2021 | 중랑구 | 1.0 | 12 | 345257 | 213 | 63 | 59 |
125 rows × 8 columns
정렬을 해도 원자료는 변하지 않는 것을 확인할 수 있다. 인덱스가 변하지 않는 것으로 확인할 수 있다.
df.head(10)
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2017 | 강남구 | 0.0 | 11 | 1565258 | 502 | 129 | 120 |
| 1 | 2017 | 강동구 | 0.0 | 12 | 418593 | 269 | 63 | 73 |
| 2 | 2017 | 강북구 | 0.0 | 6 | 339146 | 186 | 51 | 41 |
| 3 | 2017 | 강서구 | 3.0 | 22 | 706871 | 364 | 89 | 81 |
| 4 | 2017 | 관악구 | 3.0 | 20 | 654690 | 286 | 82 | 69 |
| 5 | 2017 | 광진구 | 1.0 | 6 | 433742 | 200 | 37 | 44 |
| 6 | 2017 | 구로구 | 1.0 | 5 | 460568 | 260 | 54 | 71 |
| 7 | 2017 | 금천구 | 2.0 | 7 | 605549 | 174 | 33 | 49 |
| 8 | 2017 | 노원구 | 3.0 | 18 | 566821 | 279 | 80 | 75 |
| 9 | 2017 | 도봉구 | 2.0 | 6 | 288836 | 192 | 37 | 59 |
만약 정렬된 자료를 새로 저장하고 싶으면 다음과 같이 새로운 데이터프레임으로 저장해보자.
df_copy = df.sort_values(by = '재산피해금액', ascending=False)
df_copy
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 73 | 2019 | 중구 | 3.0 | 17 | 74077097 | 213 | 51 | 39 |
| 38 | 2018 | 서대문구 | 4.0 | 9 | 7877501 | 229 | 50 | 69 |
| 85 | 2020 | 동대문구 | 6.0 | 17 | 3392558 | 152 | 43 | 34 |
| 69 | 2019 | 영등포구 | 1.0 | 48 | 3099954 | 265 | 64 | 63 |
| 123 | 2021 | 중구 | 0.0 | 16 | 2780374 | 171 | 41 | 49 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 49 | 2018 | 중랑구 | 2.0 | 8 | 201421 | 254 | 72 | 55 |
| 78 | 2020 | 강서구 | 3.0 | 5 | 200966 | 212 | 42 | 53 |
| 86 | 2020 | 동작구 | 0.0 | 7 | 194251 | 151 | 39 | 37 |
| 58 | 2019 | 노원구 | 0.0 | 6 | 185642 | 203 | 49 | 46 |
| 61 | 2019 | 동작구 | 2.0 | 10 | 179243 | 208 | 52 | 53 |
125 rows × 8 columns
또는 정렬된 자료를 원자료에 덮어씌우는 방법도 있다. 선택문 inplace = True을 입력해주면 된다.
df.sort_values(by = '재산피해금액', ascending=False, inplace=True)
df
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|---|
| 73 | 2019 | 중구 | 3.0 | 17 | 74077097 | 213 | 51 | 39 |
| 38 | 2018 | 서대문구 | 4.0 | 9 | 7877501 | 229 | 50 | 69 |
| 85 | 2020 | 동대문구 | 6.0 | 17 | 3392558 | 152 | 43 | 34 |
| 69 | 2019 | 영등포구 | 1.0 | 48 | 3099954 | 265 | 64 | 63 |
| 123 | 2021 | 중구 | 0.0 | 16 | 2780374 | 171 | 41 | 49 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 49 | 2018 | 중랑구 | 2.0 | 8 | 201421 | 254 | 72 | 55 |
| 78 | 2020 | 강서구 | 3.0 | 5 | 200966 | 212 | 42 | 53 |
| 86 | 2020 | 동작구 | 0.0 | 7 | 194251 | 151 | 39 | 37 |
| 58 | 2019 | 노원구 | 0.0 | 6 | 185642 | 203 | 49 | 46 |
| 61 | 2019 | 동작구 | 2.0 | 10 | 179243 | 208 | 52 | 53 |
125 rows × 8 columns
3. 행과 열 지우기
데이터를 정리하다 보면 특정 행과 열을 지우는 과정을 많이 하게된다. 우리의 데이터 df에서 출동횟수를 지워보자. 이 때 선택문 inplace = True으로 인하여 결과가 덮어씌워졌다.
df.drop(columns = ["출동횟수"], inplace= True)
df
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|
| 73 | 2019 | 중구 | 3.0 | 17 | 74077097 | 51 | 39 |
| 38 | 2018 | 서대문구 | 4.0 | 9 | 7877501 | 50 | 69 |
| 85 | 2020 | 동대문구 | 6.0 | 17 | 3392558 | 43 | 34 |
| 69 | 2019 | 영등포구 | 1.0 | 48 | 3099954 | 64 | 63 |
| 123 | 2021 | 중구 | 0.0 | 16 | 2780374 | 41 | 49 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 49 | 2018 | 중랑구 | 2.0 | 8 | 201421 | 72 | 55 |
| 78 | 2020 | 강서구 | 3.0 | 5 | 200966 | 42 | 53 |
| 86 | 2020 | 동작구 | 0.0 | 7 | 194251 | 39 | 37 |
| 58 | 2019 | 노원구 | 0.0 | 6 | 185642 | 49 | 46 |
| 61 | 2019 | 동작구 | 2.0 | 10 | 179243 | 52 | 53 |
125 rows × 7 columns
이번에는 행을 지워보자. 강동구에 해당하는 자료를 지우기 위해 원자료에 강동구에 해당하는 인덱스를 다음과같이 추출하였다.
26, 51, 1, 76, 101행에 강동구 자료가 있음을 알 수 있다.
index_for_delete = df[df["시군구"] == '강동구'].index
index_for_delete
Int64Index([26, 51, 1, 76, 101], dtype='int64')
인덱스로 행을 제거하기 위하여 drop 메소드를 사용한다. 마찬가지로 선택문 inplace = True로 원자료에 결과를 바로 반영하였다.
행 삭제 결과는 rows 갯수가 바뀐 것으로 확인할 수 있다.
df.drop( index = index_for_delete, inplace= True )
df
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|
| 73 | 2019 | 중구 | 3.0 | 17 | 74077097 | 51 | 39 |
| 38 | 2018 | 서대문구 | 4.0 | 9 | 7877501 | 50 | 69 |
| 85 | 2020 | 동대문구 | 6.0 | 17 | 3392558 | 43 | 34 |
| 69 | 2019 | 영등포구 | 1.0 | 48 | 3099954 | 64 | 63 |
| 123 | 2021 | 중구 | 0.0 | 16 | 2780374 | 41 | 49 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 49 | 2018 | 중랑구 | 2.0 | 8 | 201421 | 72 | 55 |
| 78 | 2020 | 강서구 | 3.0 | 5 | 200966 | 42 | 53 |
| 86 | 2020 | 동작구 | 0.0 | 7 | 194251 | 39 | 37 |
| 58 | 2019 | 노원구 | 0.0 | 6 | 185642 | 49 | 46 |
| 61 | 2019 | 동작구 | 2.0 | 10 | 179243 | 52 | 53 |
120 rows × 7 columns
5개의 행이 제거됨으로써 인덱스가 행의 갯수와 달라졌다. 따라서 인덱스를 다시 구성하기 위해보자.
인덱스를 재구성하기 위해서는 reset_index 메소드를 사용한다. 이 때 선택문 inplace = True로 원자료에 결과를 바로 반영하였다.
df.reset_index(drop=True, inplace=True)
df
| 화재발생연도 | 시군구 | 사망자수 | 부상자수 | 재산피해금액 | 출동횟수_겨울 | 출동횟수_여름 | |
|---|---|---|---|---|---|---|---|
| 0 | 2019 | 중구 | 3.0 | 17 | 74077097 | 51 | 39 |
| 1 | 2018 | 서대문구 | 4.0 | 9 | 7877501 | 50 | 69 |
| 2 | 2020 | 동대문구 | 6.0 | 17 | 3392558 | 43 | 34 |
| 3 | 2019 | 영등포구 | 1.0 | 48 | 3099954 | 64 | 63 |
| 4 | 2021 | 중구 | 0.0 | 16 | 2780374 | 41 | 49 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 115 | 2018 | 중랑구 | 2.0 | 8 | 201421 | 72 | 55 |
| 116 | 2020 | 강서구 | 3.0 | 5 | 200966 | 42 | 53 |
| 117 | 2020 | 동작구 | 0.0 | 7 | 194251 | 39 | 37 |
| 118 | 2019 | 노원구 | 0.0 | 6 | 185642 | 49 | 46 |
| 119 | 2019 | 동작구 | 2.0 | 10 | 179243 | 52 | 53 |
120 rows × 7 columns
4. 열 이름 바꾸기
자료를 정리할 때 열이름을 바꾸는 과정도 매우 흔하다. 열이름의 길이를 줄이거나, 열이름에 대한 새로운 규칙을 적용하는 등 열이름을 변경해야할 일이 자주 일어난다.
먼저 데이터프레임 df의 열이름을 확인해보자. columns메소드를 사용하면 된다.
df.columns
Index(['화재발생연도', '시군구', '사망자수', '부상자수', '재산피해금액', '출동횟수_겨울', '출동횟수_여름'], dtype='object')
열 이름을 영문으로 변경해보자. rename메소드를 사용하면 된다.
df.rename( columns={
"화재발생연도" : "year", "시군구" : "region",
"사망자수" : "samang_n", "부상자수" : "busang_n", "재산피해금액" : "money",
"출동횟수_겨울" : "win","출동횟수_여름" : "sum"},
inplace=True)
df
| year | region | samang_n | busang_n | money | win | sum | |
|---|---|---|---|---|---|---|---|
| 0 | 2019 | 중구 | 3.0 | 17 | 74077097 | 51 | 39 |
| 1 | 2018 | 서대문구 | 4.0 | 9 | 7877501 | 50 | 69 |
| 2 | 2020 | 동대문구 | 6.0 | 17 | 3392558 | 43 | 34 |
| 3 | 2019 | 영등포구 | 1.0 | 48 | 3099954 | 64 | 63 |
| 4 | 2021 | 중구 | 0.0 | 16 | 2780374 | 41 | 49 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 115 | 2018 | 중랑구 | 2.0 | 8 | 201421 | 72 | 55 |
| 116 | 2020 | 강서구 | 3.0 | 5 | 200966 | 42 | 53 |
| 117 | 2020 | 동작구 | 0.0 | 7 | 194251 | 39 | 37 |
| 118 | 2019 | 노원구 | 0.0 | 6 | 185642 | 49 | 46 |
| 119 | 2019 | 동작구 | 2.0 | 10 | 179243 | 52 | 53 |
120 rows × 7 columns
columns메소드를 통해 열 이름이 영문으로 바뀐 것을 확인할 수 있다.
df.columns
Index(['year', 'region', 'samang_n', 'busang_n', 'money', 'win', 'sum'], dtype='object')
열 이름을 바꾸는 또 다른 방법으로 리스트(list)를 사용할 수 있다. 위에서 영문으로 변경한 마지막 열의 이름을 win 에서 winter 로, sum에서 summer로 바꾸어보자.
df.columns = ['year', 'region', 'samang_n', 'busang_n', 'money', 'winter', 'summer']
df
| year | region | samang_n | busang_n | money | winter | summer | |
|---|---|---|---|---|---|---|---|
| 0 | 2019 | 중구 | 3.0 | 17 | 74077097 | 51 | 39 |
| 1 | 2018 | 서대문구 | 4.0 | 9 | 7877501 | 50 | 69 |
| 2 | 2020 | 동대문구 | 6.0 | 17 | 3392558 | 43 | 34 |
| 3 | 2019 | 영등포구 | 1.0 | 48 | 3099954 | 64 | 63 |
| 4 | 2021 | 중구 | 0.0 | 16 | 2780374 | 41 | 49 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 115 | 2018 | 중랑구 | 2.0 | 8 | 201421 | 72 | 55 |
| 116 | 2020 | 강서구 | 3.0 | 5 | 200966 | 42 | 53 |
| 117 | 2020 | 동작구 | 0.0 | 7 | 194251 | 39 | 37 |
| 118 | 2019 | 노원구 | 0.0 | 6 | 185642 | 49 | 46 |
| 119 | 2019 | 동작구 | 2.0 | 10 | 179243 | 52 | 53 |
120 rows × 7 columns
5. 데이터 프레임 요약하기
지금까지는 데이터 프레임을 정리하는 과정이었다. 이제부터는 잘 정리된 데이터를 요약해보자.
df.describe()
| year | samang_n | busang_n | money | winter | summer | |
|---|---|---|---|---|---|---|
| count | 120.000000 | 120.000000 | 120.000000 | 1.200000e+02 | 120.000000 | 120.000000 |
| mean | 2019.000000 | 1.600000 | 11.350000 | 1.353972e+06 | 58.100000 | 56.225000 |
| std | 1.420143 | 1.830645 | 8.068665 | 6.750182e+06 | 19.903718 | 18.615284 |
| min | 2017.000000 | 0.000000 | 2.000000 | 1.792430e+05 | 27.000000 | 27.000000 |
| 25% | 2018.000000 | 0.000000 | 6.000000 | 3.374510e+05 | 46.000000 | 44.750000 |
| 50% | 2019.000000 | 1.000000 | 9.000000 | 5.288170e+05 | 54.000000 | 53.000000 |
| 75% | 2020.000000 | 2.000000 | 15.000000 | 8.187352e+05 | 64.250000 | 63.250000 |
| max | 2021.000000 | 14.000000 | 48.000000 | 7.407710e+07 | 134.000000 | 125.000000 |
출력된 값을 편하게 보기 위해 단위와 반올림 등의 과정을 거친다.
df_summ = df.describe()
df_summ['samang_n'] = df_summ['samang_n'].round(2)
df_summ['busang_n'] = df_summ['busang_n'].round(2)
df_summ
| year | samang_n | busang_n | money | winter | summer | |
|---|---|---|---|---|---|---|
| count | 120.000000 | 120.00 | 120.00 | 1.200000e+02 | 120.000000 | 120.000000 |
| mean | 2019.000000 | 1.60 | 11.35 | 1.353972e+06 | 58.100000 | 56.225000 |
| std | 1.420143 | 1.83 | 8.07 | 6.750182e+06 | 19.903718 | 18.615284 |
| min | 2017.000000 | 0.00 | 2.00 | 1.792430e+05 | 27.000000 | 27.000000 |
| 25% | 2018.000000 | 0.00 | 6.00 | 3.374510e+05 | 46.000000 | 44.750000 |
| 50% | 2019.000000 | 1.00 | 9.00 | 5.288170e+05 | 54.000000 | 53.000000 |
| 75% | 2020.000000 | 2.00 | 15.00 | 8.187352e+05 | 64.250000 | 63.250000 |
| max | 2021.000000 | 14.00 | 48.00 | 7.407710e+07 | 134.000000 | 125.000000 |
df_summ['winter'] = df_summ['winter'].round(2)
df_summ['summer'] = df_summ['summer'].round(2)
df_summ
| year | samang_n | busang_n | money | winter | summer | |
|---|---|---|---|---|---|---|
| count | 120.000000 | 120.00 | 120.00 | 1.200000e+02 | 120.00 | 120.00 |
| mean | 2019.000000 | 1.60 | 11.35 | 1.353972e+06 | 58.10 | 56.22 |
| std | 1.420143 | 1.83 | 8.07 | 6.750182e+06 | 19.90 | 18.62 |
| min | 2017.000000 | 0.00 | 2.00 | 1.792430e+05 | 27.00 | 27.00 |
| 25% | 2018.000000 | 0.00 | 6.00 | 3.374510e+05 | 46.00 | 44.75 |
| 50% | 2019.000000 | 1.00 | 9.00 | 5.288170e+05 | 54.00 | 53.00 |
| 75% | 2020.000000 | 2.00 | 15.00 | 8.187352e+05 | 64.25 | 63.25 |
| max | 2021.000000 | 14.00 | 48.00 | 7.407710e+07 | 134.00 | 125.00 |
df_summ['money'] = df_summ['money'] / 10000
df_summ['money'] = df_summ['money'].round(4)
df_summ
| year | samang_n | busang_n | money | winter | summer | |
|---|---|---|---|---|---|---|
| count | 120.000000 | 120.00 | 120.00 | 0.0120 | 120.00 | 120.00 |
| mean | 2019.000000 | 1.60 | 11.35 | 135.3972 | 58.10 | 56.22 |
| std | 1.420143 | 1.83 | 8.07 | 675.0182 | 19.90 | 18.62 |
| min | 2017.000000 | 0.00 | 2.00 | 17.9243 | 27.00 | 27.00 |
| 25% | 2018.000000 | 0.00 | 6.00 | 33.7451 | 46.00 | 44.75 |
| 50% | 2019.000000 | 1.00 | 9.00 | 52.8817 | 54.00 | 53.00 |
| 75% | 2020.000000 | 2.00 | 15.00 | 81.8735 | 64.25 | 63.25 |
| max | 2021.000000 | 14.00 | 48.00 | 7407.7097 | 134.00 | 125.00 |
df_summ.columns = ['화재발생연도', '사망자수', '부상자수', '재산피해금액(만원)', '출동횟수(겨울)', '출동횟수(여름)']
df_summ
| 화재발생연도 | 사망자수 | 부상자수 | 재산피해금액(만원) | 출동횟수(겨울) | 출동횟수(여름) | |
|---|---|---|---|---|---|---|
| count | 120.000000 | 120.00 | 120.00 | 0.0120 | 120.00 | 120.00 |
| mean | 2019.000000 | 1.60 | 11.35 | 135.3972 | 58.10 | 56.22 |
| std | 1.420143 | 1.83 | 8.07 | 675.0182 | 19.90 | 18.62 |
| min | 2017.000000 | 0.00 | 2.00 | 17.9243 | 27.00 | 27.00 |
| 25% | 2018.000000 | 0.00 | 6.00 | 33.7451 | 46.00 | 44.75 |
| 50% | 2019.000000 | 1.00 | 9.00 | 52.8817 | 54.00 | 53.00 |
| 75% | 2020.000000 | 2.00 | 15.00 | 81.8735 | 64.25 | 63.25 |
| max | 2021.000000 | 14.00 | 48.00 | 7407.7097 | 134.00 | 125.00 |
df_summ = df_summ.drop(columns = '화재발생연도')
df_summ
| 사망자수 | 부상자수 | 재산피해금액(만원) | 출동횟수(겨울) | 출동횟수(여름) | |
|---|---|---|---|---|---|
| count | 120.00 | 120.00 | 0.0120 | 120.00 | 120.00 |
| mean | 1.60 | 11.35 | 135.3972 | 58.10 | 56.22 |
| std | 1.83 | 8.07 | 675.0182 | 19.90 | 18.62 |
| min | 0.00 | 2.00 | 17.9243 | 27.00 | 27.00 |
| 25% | 0.00 | 6.00 | 33.7451 | 46.00 | 44.75 |
| 50% | 1.00 | 9.00 | 52.8817 | 54.00 | 53.00 |
| 75% | 2.00 | 15.00 | 81.8735 | 64.25 | 63.25 |
| max | 14.00 | 48.00 | 7407.7097 | 134.00 | 125.00 |
이번에는 특정 범주를 기준으로 자료를 요약해보자. 이 때 기준은 연도와 ‘시군구`로 한다.
먼저 2021년도의 데이터를 추출해보자.
df_2021 = df.loc[df['year']==2021]
df_2021
| year | region | samang_n | busang_n | money | winter | summer | |
|---|---|---|---|---|---|---|---|
| 4 | 2021 | 중구 | 0.0 | 16 | 2780374 | 41 | 49 |
| 7 | 2021 | 구로구 | 1.0 | 7 | 1765589 | 52 | 33 |
| 13 | 2021 | 강남구 | 2.0 | 15 | 1354949 | 112 | 91 |
| 16 | 2021 | 동대문구 | 3.0 | 15 | 1209541 | 51 | 40 |
| 24 | 2021 | 영등포구 | 0.0 | 8 | 913698 | 50 | 53 |
| 25 | 2021 | 광진구 | 2.0 | 10 | 889681 | 46 | 56 |
| 26 | 2021 | 은평구 | 3.0 | 8 | 875722 | 57 | 42 |
| 29 | 2021 | 금천구 | 2.0 | 8 | 825255 | 37 | 28 |
| 32 | 2021 | 송파구 | 1.0 | 5 | 788289 | 64 | 59 |
| 52 | 2021 | 마포구 | 2.0 | 7 | 591687 | 64 | 53 |
| 53 | 2021 | 양천구 | 2.0 | 3 | 576094 | 42 | 42 |
| 56 | 2021 | 관악구 | 2.0 | 17 | 562294 | 74 | 54 |
| 57 | 2021 | 강서구 | 2.0 | 12 | 559614 | 61 | 50 |
| 59 | 2021 | 서초구 | 0.0 | 9 | 549807 | 69 | 51 |
| 62 | 2021 | 성북구 | 4.0 | 46 | 493231 | 56 | 37 |
| 67 | 2021 | 종로구 | 0.0 | 12 | 465499 | 48 | 54 |
| 70 | 2021 | 성동구 | 0.0 | 5 | 458412 | 48 | 54 |
| 72 | 2021 | 노원구 | 1.0 | 12 | 432605 | 48 | 49 |
| 76 | 2021 | 강북구 | 5.0 | 14 | 410205 | 29 | 38 |
| 88 | 2021 | 중랑구 | 1.0 | 12 | 345257 | 63 | 59 |
| 94 | 2021 | 동작구 | 3.0 | 9 | 307365 | 42 | 27 |
| 96 | 2021 | 용산구 | 0.0 | 5 | 296793 | 47 | 36 |
| 103 | 2021 | 서대문구 | 0.0 | 7 | 249728 | 77 | 52 |
| 107 | 2021 | 도봉구 | 0.0 | 6 | 219916 | 33 | 34 |
df_2021.describe()
| year | samang_n | busang_n | money | winter | summer | |
|---|---|---|---|---|---|---|
| count | 24.0 | 24.000000 | 24.000000 | 2.400000e+01 | 24.000000 | 24.000000 |
| mean | 2021.0 | 1.500000 | 11.166667 | 7.467335e+05 | 54.625000 | 47.541667 |
| std | 0.0 | 1.414214 | 8.370064 | 5.714713e+05 | 17.337601 | 13.354625 |
| min | 2021.0 | 0.000000 | 3.000000 | 2.199160e+05 | 29.000000 | 27.000000 |
| 25% | 2021.0 | 0.000000 | 7.000000 | 4.270050e+05 | 45.000000 | 37.750000 |
| 50% | 2021.0 | 1.500000 | 9.000000 | 5.609540e+05 | 50.500000 | 49.500000 |
| 75% | 2021.0 | 2.000000 | 12.500000 | 8.792118e+05 | 63.250000 | 54.000000 |
| max | 2021.0 | 5.000000 | 46.000000 | 2.780374e+06 | 112.000000 | 91.000000 |
describe메소드로 자료를 요약한다. 이 때 표현방식을 바꾸고싶다면 위의 과정을 동일하게 거치면 된다. (실습)
접기/펼치기
df2021_summ = df_2021.describe()
df2021_summ[‘samang_n’] = df2021_summ[‘samang_n’].round(2)
df2021_summ[‘busang_n’] = df2021_summ[‘busang_n’].round(2)
df2021_summ[‘winter’] = df2021_summ[‘winter’].round(2)
df2021_summ[‘summer’] = df2021_summ[‘summer’].round(2)
df2021_summ[‘money’] = df2021_summ[‘money’] / 10000
df2021_summ[‘money’] = df2021_summ[‘money’].round(4)
df2021_summ.columns = [‘화재발생연도’, ‘사망자수’, ‘부상자수’, ‘재산피해금액(만원)’, ‘출동횟수(겨울)’, ‘출동횟수(여름)’]
df2021_summ = df2021_summ.drop(columns = ‘화재발생연도’)
df2021_summ
추가적으로, 재산피해금액(만원)을 반올림하면서 count값도 같이 변형되었다. 해당 셀을 수정하고자 한다.
인덱싱을 수행하는 또 다른 메소드 iloc으로 해당 셀(cell)만 값 변경이 가능하다. 아래 코드의 iloc[0,2]는 0행 2열을 의미한다.
접기/펼치기
df2021_summ.iloc[0,2] = 24
df2021_summ
2021년 중에 여름과 겨울의 출동 횟수가 많은 지역구대로 정렬 해보자.
정렬하기 위해서는 sort_values()메소드를 사용한다. 괄호 안에 정렬할 열을 지정한다. 내림차순으로 정렬도 해보자 (실습)
df_2021.sort_values(by="winter")
| year | region | samang_n | busang_n | money | winter | summer | |
|---|---|---|---|---|---|---|---|
| 76 | 2021 | 강북구 | 5.0 | 14 | 410205 | 29 | 38 |
| 107 | 2021 | 도봉구 | 0.0 | 6 | 219916 | 33 | 34 |
| 29 | 2021 | 금천구 | 2.0 | 8 | 825255 | 37 | 28 |
| 4 | 2021 | 중구 | 0.0 | 16 | 2780374 | 41 | 49 |
| 53 | 2021 | 양천구 | 2.0 | 3 | 576094 | 42 | 42 |
| 94 | 2021 | 동작구 | 3.0 | 9 | 307365 | 42 | 27 |
| 25 | 2021 | 광진구 | 2.0 | 10 | 889681 | 46 | 56 |
| 96 | 2021 | 용산구 | 0.0 | 5 | 296793 | 47 | 36 |
| 67 | 2021 | 종로구 | 0.0 | 12 | 465499 | 48 | 54 |
| 70 | 2021 | 성동구 | 0.0 | 5 | 458412 | 48 | 54 |
| 72 | 2021 | 노원구 | 1.0 | 12 | 432605 | 48 | 49 |
| 24 | 2021 | 영등포구 | 0.0 | 8 | 913698 | 50 | 53 |
| 16 | 2021 | 동대문구 | 3.0 | 15 | 1209541 | 51 | 40 |
| 7 | 2021 | 구로구 | 1.0 | 7 | 1765589 | 52 | 33 |
| 62 | 2021 | 성북구 | 4.0 | 46 | 493231 | 56 | 37 |
| 26 | 2021 | 은평구 | 3.0 | 8 | 875722 | 57 | 42 |
| 57 | 2021 | 강서구 | 2.0 | 12 | 559614 | 61 | 50 |
| 88 | 2021 | 중랑구 | 1.0 | 12 | 345257 | 63 | 59 |
| 32 | 2021 | 송파구 | 1.0 | 5 | 788289 | 64 | 59 |
| 52 | 2021 | 마포구 | 2.0 | 7 | 591687 | 64 | 53 |
| 59 | 2021 | 서초구 | 0.0 | 9 | 549807 | 69 | 51 |
| 56 | 2021 | 관악구 | 2.0 | 17 | 562294 | 74 | 54 |
| 103 | 2021 | 서대문구 | 0.0 | 7 | 249728 | 77 | 52 |
| 13 | 2021 | 강남구 | 2.0 | 15 | 1354949 | 112 | 91 |
df_2021.sort_values(by="summer")
| year | region | samang_n | busang_n | money | winter | summer | |
|---|---|---|---|---|---|---|---|
| 94 | 2021 | 동작구 | 3.0 | 9 | 307365 | 42 | 27 |
| 29 | 2021 | 금천구 | 2.0 | 8 | 825255 | 37 | 28 |
| 7 | 2021 | 구로구 | 1.0 | 7 | 1765589 | 52 | 33 |
| 107 | 2021 | 도봉구 | 0.0 | 6 | 219916 | 33 | 34 |
| 96 | 2021 | 용산구 | 0.0 | 5 | 296793 | 47 | 36 |
| 62 | 2021 | 성북구 | 4.0 | 46 | 493231 | 56 | 37 |
| 76 | 2021 | 강북구 | 5.0 | 14 | 410205 | 29 | 38 |
| 16 | 2021 | 동대문구 | 3.0 | 15 | 1209541 | 51 | 40 |
| 53 | 2021 | 양천구 | 2.0 | 3 | 576094 | 42 | 42 |
| 26 | 2021 | 은평구 | 3.0 | 8 | 875722 | 57 | 42 |
| 4 | 2021 | 중구 | 0.0 | 16 | 2780374 | 41 | 49 |
| 72 | 2021 | 노원구 | 1.0 | 12 | 432605 | 48 | 49 |
| 57 | 2021 | 강서구 | 2.0 | 12 | 559614 | 61 | 50 |
| 59 | 2021 | 서초구 | 0.0 | 9 | 549807 | 69 | 51 |
| 103 | 2021 | 서대문구 | 0.0 | 7 | 249728 | 77 | 52 |
| 52 | 2021 | 마포구 | 2.0 | 7 | 591687 | 64 | 53 |
| 24 | 2021 | 영등포구 | 0.0 | 8 | 913698 | 50 | 53 |
| 56 | 2021 | 관악구 | 2.0 | 17 | 562294 | 74 | 54 |
| 70 | 2021 | 성동구 | 0.0 | 5 | 458412 | 48 | 54 |
| 67 | 2021 | 종로구 | 0.0 | 12 | 465499 | 48 | 54 |
| 25 | 2021 | 광진구 | 2.0 | 10 | 889681 | 46 | 56 |
| 32 | 2021 | 송파구 | 1.0 | 5 | 788289 | 64 | 59 |
| 88 | 2021 | 중랑구 | 1.0 | 12 | 345257 | 63 | 59 |
| 13 | 2021 | 강남구 | 2.0 | 15 | 1354949 | 112 | 91 |
이어서 강남구 기준으로 자료를 살펴보자.
df_강남구 = df.loc[df['region']=="강남구"]
df_강남구
| year | region | samang_n | busang_n | money | winter | summer | |
|---|---|---|---|---|---|---|---|
| 8 | 2019 | 강남구 | 1.0 | 23 | 1677681 | 120 | 125 |
| 9 | 2018 | 강남구 | 0.0 | 23 | 1624983 | 134 | 111 |
| 10 | 2017 | 강남구 | 0.0 | 11 | 1565258 | 129 | 120 |
| 11 | 2020 | 강남구 | 1.0 | 18 | 1451556 | 100 | 98 |
| 13 | 2021 | 강남구 | 2.0 | 15 | 1354949 | 112 | 91 |
강남구의 기초 통계량을 확인해보자.
df_강남구.describe()
| year | samang_n | busang_n | money | winter | summer | |
|---|---|---|---|---|---|---|
| count | 5.000000 | 5.00000 | 5.000000 | 5.000000e+00 | 5.00000 | 5.000000 |
| mean | 2019.000000 | 0.80000 | 18.000000 | 1.534885e+06 | 119.00000 | 109.000000 |
| std | 1.581139 | 0.83666 | 5.196152 | 1.311026e+05 | 13.56466 | 14.370108 |
| min | 2017.000000 | 0.00000 | 11.000000 | 1.354949e+06 | 100.00000 | 91.000000 |
| 25% | 2018.000000 | 0.00000 | 15.000000 | 1.451556e+06 | 112.00000 | 98.000000 |
| 50% | 2019.000000 | 1.00000 | 18.000000 | 1.565258e+06 | 120.00000 | 111.000000 |
| 75% | 2020.000000 | 1.00000 | 23.000000 | 1.624983e+06 | 129.00000 | 120.000000 |
| max | 2021.000000 | 2.00000 | 23.000000 | 1.677681e+06 | 134.00000 | 125.000000 |
강남구에서 여름과 겨울의 총 출동이 많았던 연도 순으로 정렬해보자. (실습)
접기/펼치기
df_강남구[‘총 출동’] = df_강남구[‘winter’] + df_강남구[‘summer’]
df_강남구.sort_values(by = ‘총 출동’, ascending=False)
df_강남구 데이터에 대해 추가적으로 다음의 작업을 해보자 (실습)
인덱싱 재정리 (
reset_index)열 이름 변경:
['연도', '시군구', '사망자수', '부상자수', '피해금액', '겨울출동건수', '여름출동건수', '총출동']csv 파일로 저장
접기/펼치기
df_강남구.columns = [‘연도’, ‘시군구’, ‘사망자수’, ‘부상자수’, ‘피해금액’, ‘겨울출동건수’, ‘여름출동건수’, ‘총출동’]
df_강남구.reset_index(drop = True, inplace = True)
df_강남구.to_csv(“강남구요약.csv”, encoding = ‘cp949’)