11wk-2

자료분석
pandas backend
plotly
Author

최규빈

Published

November 16, 2022

자료분석– 저출산자료 시각화

강의영상

https://youtube.com/playlist?list=PLQqh36zP38-ySZ1qjl8-3RrHjoFNetGMG

imports

import pandas as pd 
import numpy as np

자료분석: 저출산

데이터읽기 // pd.read_html()

- 대한민국의 저출산문제

  • ref: https://ko.wikipedia.org/wiki/대한민국의_저출산

- 위의 url에서 3,5번째 테이블을 읽고싶다. - 3번째 테이블: 시도별 출산율 - 5번째 테이블: 시도별 출생아 수

_dflst = pd.read_html('https://ko.wikipedia.org/wiki/%EB%8C%80%ED%95%9C%EB%AF%BC%EA%B5%AD%EC%9D%98_%EC%A0%80%EC%B6%9C%EC%82%B0')
_df1 = _dflst[2] 
_df2 = _dflst[4] 
_df1
지역/연도[6] 2005 2006[7] 2007 2008[8] 2009[9] 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021
0 서울 0.92 0.97 1.06 1.01 0.96 1.02 1.01 1.06 0.97 0.98 1.00 0.94 0.84 0.76 0.72 0.64 0.63
1 부산 0.88 0.91 1.02 0.98 0.94 1.05 1.08 1.14 1.05 1.09 1.14 1.10 0.98 0.90 0.83 0.75 0.73
2 대구 0.99 1.00 1.13 1.07 1.03 1.11 1.15 1.22 1.13 1.17 1.22 1.19 1.07 0.99 0.93 0.81 0.78
3 인천 1.07 1.11 1.25 1.19 1.14 1.21 1.23 1.30 1.20 1.21 1.22 1.14 1.01 1.01 0.94 0.83 0.78
4 광주 1.10 1.14 1.26 1.20 1.14 1.22 1.23 1.30 1.17 1.20 1.21 1.17 1.05 0.97 0.91 0.81 0.90
5 대전 1.10 1.15 1.27 1.22 1.16 1.21 1.26 1.32 1.23 1.25 1.28 1.19 1.08 0.95 0.88 0.81 0.81
6 울산 1.18 1.24 1.40 1.34 1.31 1.37 1.39 1.48 1.39 1.44 1.49 1.42 1.26 1.13 1.08 0.99 0.94
7 세종 - - - - - - - 1.60 1.44 1.35 1.89 1.82 1.67 1.57 1.47 1.28 1.28
8 경기 1.17 1.23 1.35 1.29 1.23 1.31 1.31 1.36 1.23 1.24 1.27 1.19 1.07 1.00 0.94 0.88 0.85
9 강원 1.18 1.19 1.35 1.25 1.25 1.31 1.34 1.37 1.25 1.25 1.31 1.24 1.12 1.07 1.08 1.04 0.98
10 충북 1.19 1.22 1.39 1.32 1.32 1.40 1.43 1.49 1.37 1.36 1.41 1.36 1.24 1.17 1.05 0.98 0.95
11 충남 1.26 1.35 1.50 1.44 1.41 1.48 1.50 1.57 1.44 1.42 1.48 1.40 1.28 1.19 1.11 1.03 0.96
12 전북 1.17 1.20 1.37 1.31 1.28 1.37 1.41 1.44 1.32 1.33 1.35 1.25 1.15 1.04 0.97 0.91 0.85
13 전남 1.28 1.33 1.53 1.45 1.45 1.54 1.57 1.64 1.52 1.50 1.55 1.47 1.33 1.24 1.23 1.15 1.02
14 경북 1.17 1.20 1.36 1.31 1.27 1.38 1.43 1.49 1.38 1.41 1.46 1.40 1.26 1.17 1.09 1.00 0.97
15 경남 1.18 1.25 1.43 1.37 1.32 1.41 1.45 1.50 1.37 1.41 1.44 1.36 1.23 1.12 1.05 0.95 0.90
16 제주 1.30 1.36 1.48 1.39 1.38 1.46 1.49 1.60 1.43 1.48 1.48 1.43 1.31 1.22 1.15 1.02 0.95
17 전국 1.08 1.13 1.25 1.19 1.15 1.23 1.24 1.30 1.19 1.21 1.24 1.17 1.05 0.98 0.92 0.84 0.81
_df2
지역/연도[6] 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021
0 서울 93266 91526 93914.000 84066.000 83711.000 83005 75.536 65389 58074 53.673 47400 45531
1 부산 27415 27759 28673.000 25831.000 26190.000 26645 24906.000 21480 19152 17049.000 15100 14446
2 대구 20557 20758 21472.000 19340.000 19361.000 19438 18298.000 15946 14400 13233.000 11200 10661
3 인천 25752 20758 21472.000 25560.000 25786.000 25491 23609.000 20445 20087 18522.000 16000 14947
4 광주 13979 13916 14392.000 12729.000 12729.000 12441 11580.000 10120 9105 8364.000 7300 7956
5 대전 14314 14808 15279.000 14099.000 13962.000 13774 12436.000 10851 9337 8410.000 7500 7414
6 울산 11432 11542 12160.000 11330.000 11556.000 11732 10910.000 9381 8149 7539.000 6600 6127
7 세종 - - 1054.000 1111.000 1344.000 2708 3297.000 3504 3703 3819.000 3500 3570
8 경기 121753 122027 124746.000 112129.000 112.169 113495 105643.000 94088 83198 83.198 77800 76139
9 강원 12477 12408 12426.000 10980.000 10662.000 10929 10058.000 9958 8351 8283.000 7800 7357
10 충북 14670 14804 15139.000 13658.000 13366.000 13563 12742.000 11394 10586 9333.000 8600 8190
11 충남 20.242 20.398 20.448 18.628 18200.000 18604 17302.000 15670 14380 13228.000 11900 10984
12 전북 16100 16175 16238.000 14555.000 14231.000 14087 12698.000 11348 10001 8971.000 8200 7745
13 전남 16654 16612 16990.000 15401.000 14817.000 15061 13980.000 12354 11238 10832.000 9700 8430
14 경북 23700 24250 24635.000 22206.000 22062.000 22310 20616.000 17957 16079 14472.000 12900 12045
15 경남 32203 32536 33211.000 29504.000 29763.000 29537 27138.000 23849 21224 19250.000 16800 15562
16 제주 5657 5628 5992.000 5328.000 5526.000 5600 5494.000 5037 4781 4500.000 4000 3728
17 전국 470171 471265 484550.000 436455.000 435435.000 438420 406243.000 357771 326822 302676.000 272400 260562

- 데이터정리

df1 = _df1.drop(17)\
.melt(id_vars='지역/연도[6]')\
.assign(variable = lambda df: list(map(lambda x: x[:4], df.variable)))\
.assign(value = lambda df: list(map(lambda x: None if x=='-' else float(x), df.value)))\
.set_axis(['지역','연도','출산율'],axis=1)
df1
지역 연도 출산율
0 서울 2005 0.92
1 부산 2005 0.88
2 대구 2005 0.99
3 인천 2005 1.07
4 광주 2005 1.10
... ... ... ...
284 전북 2021 0.85
285 전남 2021 1.02
286 경북 2021 0.97
287 경남 2021 0.90
288 제주 2021 0.95

289 rows × 3 columns

df2 = _df2.drop(17)\
.melt(id_vars='지역/연도[6]')\
.assign(value = lambda df: list(map(lambda x: None if x=='-' else float(x), df.value)))\
.set_axis(['지역','연도','출생아수'],axis=1)
df2
지역 연도 출생아수
0 서울 2010 93266.0
1 부산 2010 27415.0
2 대구 2010 20557.0
3 인천 2010 25752.0
4 광주 2010 13979.0
... ... ... ...
199 전북 2021 7745.0
200 전남 2021 8430.0
201 경북 2021 12045.0
202 경남 2021 15562.0
203 제주 2021 3728.0

204 rows × 3 columns

시각화I: 전국 출생아수 시각화

df2.groupby(['연도'])\
.agg({'출생아수':np.sum})\
.reset_index()\
.plot(x='연도',y='출생아수',backend='plotly')
  • 일괄적으로 감소하는 느낌은 없음

시각화II: 시도별 출생아수 시각화

- 시각화예시1

df2.plot.line(backend='plotly', x='연도',y='출생아수',color='지역')
  • 서울과 경기가 특이함

- 시각화예시2

df2.plot.area(backend='plotly',x='연도',y='출생아수',color='지역')
  • areaplot의 최상단의 선: 전국출생아수 시각화와 같음 (일괄적으로 감소하는 느낌은 별로 없음, 그 이유를 살펴보니 서울과 경기지역 떄문임)
  • areaplot의 장점: 전국출생아수를 년도별로 시각화 하는 느낌 + 각 연도를 도시별로 분해하여 해석하는 느낌

시각화III: 시도별 출산율 시각화

df1.plot.line(backend='plotly',x='연도',y='출산율',color='지역')
  • 상식과 일치하는 정상적인 플랏 (출산율이 2012년 이후로 꺽이는 느낌이 든다)
  • 여기서는 서울/경기가 정상인듯 보인다.

출산율의 경우 합계출산율이 크게 의미가 없으므로 areaplot은 생략한다.

해석

- 이상한점: 서울/경기지역에서 특정연도의 출생아수가 매우 낮음. 그런데 서울/경기지역의 출산율은 모든 년도에서 고른값을 가짐.

- 해석: 데이터가 이상하다.. // 위키를 살펴보니 오타가 있음!!

데이터의 수정 (1): df2 상태에서 수정

- df2의 수정

df2.sort_values("출생아수")[:10]
지역 연도 출생아수
62 충남 2013 18.628
11 충남 2010 20.242
28 충남 2011 20.398
45 충남 2012 20.448
153 서울 2019 53.673
102 서울 2016 75.536
161 경기 2019 83.198
76 경기 2014 112.169
41 세종 2012 1054.000
58 세종 2013 1111.000

- 오타로 예상되는 서울/경기/충남 이외의 가장 작은 값은 2012년 세종시인데, 이 값이 1054로 1000보다 크다.

  • 출생아수 < 1000 이면 출생아수 * 1000 을 수행하는 함수를 구현하자.
df2.assign(출생아수= list(map(lambda x: x*1000 if x<1000 else x, df2.출생아수)))
지역 연도 출생아수
0 서울 2010 93266.0
1 부산 2010 27415.0
2 대구 2010 20557.0
3 인천 2010 25752.0
4 광주 2010 13979.0
... ... ... ...
199 전북 2021 7745.0
200 전남 2021 8430.0
201 경북 2021 12045.0
202 경남 2021 15562.0
203 제주 2021 3728.0

204 rows × 3 columns

- 잘 변환되었는지 확인하기 위한 시각화

df2.assign(출생아수= list(map(lambda x: x*1000 if x<1000 else x, df2.출생아수)))\
.plot.area(x='연도',y='출생아수',color='지역',backend='plotly')
  • 상식적인 결과: 전체출산율이 점점 낮아지고 있고 항목별로 살펴보아도 모든 도시의 출생아수가 점차 낮아지고 있음

데이터의 수정 (2): _df2 상태에서 수정

- applymap

_df2.set_index('지역/연도[6]') # applymap을 쓰기 위해서 임시로 지역/연도[6]을 인덱스로만듬 
2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021
지역/연도[6]
서울 93266 91526 93914.000 84066.000 83711.000 83005 75.536 65389 58074 53.673 47400 45531
부산 27415 27759 28673.000 25831.000 26190.000 26645 24906.000 21480 19152 17049.000 15100 14446
대구 20557 20758 21472.000 19340.000 19361.000 19438 18298.000 15946 14400 13233.000 11200 10661
인천 25752 20758 21472.000 25560.000 25786.000 25491 23609.000 20445 20087 18522.000 16000 14947
광주 13979 13916 14392.000 12729.000 12729.000 12441 11580.000 10120 9105 8364.000 7300 7956
대전 14314 14808 15279.000 14099.000 13962.000 13774 12436.000 10851 9337 8410.000 7500 7414
울산 11432 11542 12160.000 11330.000 11556.000 11732 10910.000 9381 8149 7539.000 6600 6127
세종 - - 1054.000 1111.000 1344.000 2708 3297.000 3504 3703 3819.000 3500 3570
경기 121753 122027 124746.000 112129.000 112.169 113495 105643.000 94088 83198 83.198 77800 76139
강원 12477 12408 12426.000 10980.000 10662.000 10929 10058.000 9958 8351 8283.000 7800 7357
충북 14670 14804 15139.000 13658.000 13366.000 13563 12742.000 11394 10586 9333.000 8600 8190
충남 20.242 20.398 20.448 18.628 18200.000 18604 17302.000 15670 14380 13228.000 11900 10984
전북 16100 16175 16238.000 14555.000 14231.000 14087 12698.000 11348 10001 8971.000 8200 7745
전남 16654 16612 16990.000 15401.000 14817.000 15061 13980.000 12354 11238 10832.000 9700 8430
경북 23700 24250 24635.000 22206.000 22062.000 22310 20616.000 17957 16079 14472.000 12900 12045
경남 32203 32536 33211.000 29504.000 29763.000 29537 27138.000 23849 21224 19250.000 16800 15562
제주 5657 5628 5992.000 5328.000 5526.000 5600 5494.000 5037 4781 4500.000 4000 3728
전국 470171 471265 484550.000 436455.000 435435.000 438420 406243.000 357771 326822 302676.000 272400 260562

- 방법1

_df2.set_index('지역/연도[6]')\
.applymap(lambda x: None if x == '-' else float(x))\
.applymap(lambda x: x*1000 if x<1000 else x)\
.drop('전국')\
.stack().reset_index()
지역/연도[6] level_1 0
0 서울 2010 93266.0
1 서울 2011 91526.0
2 서울 2012 93914.0
3 서울 2013 84066.0
4 서울 2014 83711.0
... ... ... ...
197 제주 2017 5037.0
198 제주 2018 4781.0
199 제주 2019 4500.0
200 제주 2020 4000.0
201 제주 2021 3728.0

202 rows × 3 columns

- 방법2

df2 = _df2.set_index('지역/연도[6]')\
.applymap(lambda x: None if x == '-' else float(x))\
.applymap(lambda x: x*1000 if x<1000 else x)\
.drop('전국')\
.reset_index()\
.melt(id_vars='지역/연도[6]')\
.set_axis(['지역','연도','출생아수'],axis=1)
df2
지역 연도 출생아수
0 서울 2010 93266.0
1 부산 2010 27415.0
2 대구 2010 20557.0
3 인천 2010 25752.0
4 광주 2010 13979.0
... ... ... ...
199 전북 2021 7745.0
200 전남 2021 8430.0
201 경북 2021 12045.0
202 경남 2021 15562.0
203 제주 2021 3728.0

204 rows × 3 columns

df2.plot.area(backend='plotly',x='연도',y='출생아수',color='지역')

숙제

아래와 같은 통계량을 구하라.

  • \(서울_{2010} = \frac{\text{2010년 서울의 출생자 수}}{\text{2010년 출생자수}}, \dots, 서울_{2021} = \frac{\text{2021년 서울의 출생자 수}}{\text{2021년 출생자수}}\)

참고로 계산결과는 [0.198, 0.196, 0.196, 0.193, 0.192, 0.189, 0.186, 0.182, 0.18, 0.177, 0.174, 0.175] 와 같다.

lineplot을 이용하여 아래와 같이 시각화 하라.

(풀이)

df2.groupby('연도')[['출생아수']].sum().reset_index().rename({'출생아수':'년도별출생아수합'},axis=1).\
merge(df2).eval('ratio = 출생아수/년도별출생아수합').query('지역=="서울"').\
plot.line(x='연도',y='ratio',backend='plotly')