우리나라 인구 소명 위기 지역 분석¶
인구 소멸 위기 지역:¶
‘한국의 ‘지방소멸' 65세 이상 노인 인구와 20∼39세 여성 인구를 비교해 젊은 여성 인구가 노인 인구의 절반에 미달할 경우 ‘소멸 위험 지역’으로 분류하는 방식
- 국가통계포털(KOSIS) https://kosis.kr/index/index.do
인구데이터 확보하고 정리하기¶
In [1]:
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import platform import warnings warnings.filterwarnings(action='ignore') path = "C:/Windows/Fonts/malgun.ttf" from matplotlib import font_manager, rc if platform.system() == 'Darwin': rc('font', family='AppleGothic') elif platform.system() == 'Windows': font_name = font_manager.FontProperties(fname=path).get_name() rc('font', family=font_name) else: print('Unknown system... sorry~~~~')
In [2]:
population = pd.read_excel('../../data/05. population_raw_data.xlsx', header=1) population
Out[2]:
행정구역(동읍면)별(1) | 행정구역(동읍면)별(2) | 항목 | 계 | 20 - 24세 | 25 - 29세 | 30 - 34세 | 35 - 39세 | 65 - 69세 | 70 - 74세 | 75 - 79세 | 80 - 84세 | 85 - 89세 | 90 - 94세 | 95 - 99세 | 100+ | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 전국 | 소계 | 총인구수 (명) | 51696216.0 | 3541061.0 | 3217367.0 | 3517868 | 4016272.0 | 2237345.0 | 1781229.0 | 1457890 | 909130.0 | 416164.0 | 141488.0 | 34844 | 17562.0 |
1 | NaN | NaN | 남자인구수 (명) | 25827594.0 | 1877127.0 | 1682988.0 | 1806754 | 2045265.0 | 1072395.0 | 806680.0 | 600607 | 319391.0 | 113221.0 | 32695.0 | 7658 | 4137.0 |
2 | NaN | NaN | 여자인구수 (명) | 25868622.0 | 1663934.0 | 1534379.0 | 1711114 | 1971007.0 | 1164950.0 | 974549.0 | 857283 | 589739.0 | 302943.0 | 108793.0 | 27186 | 13425.0 |
3 | 서울특별시 | 소계 | 총인구수 (명) | 9930616.0 | 690728.0 | 751973.0 | 803507 | 817467.0 | 448956.0 | 350580.0 | 251961 | 141649.0 | 66067.0 | 24153.0 | 7058 | 5475.0 |
4 | NaN | NaN | 남자인구수 (명) | 4876789.0 | 347534.0 | 372249.0 | 402358 | 410076.0 | 211568.0 | 163766.0 | 112076 | 54033.0 | 19595.0 | 6146.0 | 1900 | 1406.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
841 | NaN | NaN | 남자인구수 (명) | 235977.0 | 17377.0 | 13118.0 | 15084 | 18350.0 | 8474.0 | 6782.0 | 4941 | 2737.0 | 854.0 | 226.0 | 53 | 17.0 |
842 | NaN | NaN | 여자인구수 (명) | 234688.0 | 15261.0 | 12245.0 | 14687 | 18062.0 | 9265.0 | 7877.0 | 7178 | 5649.0 | 3122.0 | 1387.0 | 460 | 137.0 |
843 | NaN | 서귀포시 | 총인구수 (명) | 170932.0 | 10505.0 | 8067.0 | 9120 | 11606.0 | 8686.0 | 7460.0 | 6456 | 4521.0 | 1855.0 | 733.0 | 242 | 77.0 |
844 | NaN | NaN | 남자인구수 (명) | 86568.0 | 5600.0 | 4247.0 | 4693 | 6082.0 | 4237.0 | 3441.0 | 2611 | 1494.0 | 370.0 | 103.0 | 29 | 9.0 |
845 | NaN | NaN | 여자인구수 (명) | 84364.0 | 4905.0 | 3820.0 | 4427 | 5524.0 | 4449.0 | 4019.0 | 3845 | 3027.0 | 1485.0 | 630.0 | 213 | 68.0 |
846 rows × 16 columns
In [3]:
population.rename(columns = {'항목':'구분'}, inplace=True) population.loc[population['구분'] == '총인구수 (명)', '구분'] = '합계' population.loc[population['구분'] == '남자인구수 (명)', '구분'] = '남자' population.loc[population['구분'] == '여자인구수 (명)', '구분'] = '여자' population
Out[3]:
행정구역(동읍면)별(1) | 행정구역(동읍면)별(2) | 구분 | 계 | 20 - 24세 | 25 - 29세 | 30 - 34세 | 35 - 39세 | 65 - 69세 | 70 - 74세 | 75 - 79세 | 80 - 84세 | 85 - 89세 | 90 - 94세 | 95 - 99세 | 100+ | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 전국 | 소계 | 합계 | 51696216.0 | 3541061.0 | 3217367.0 | 3517868 | 4016272.0 | 2237345.0 | 1781229.0 | 1457890 | 909130.0 | 416164.0 | 141488.0 | 34844 | 17562.0 |
1 | NaN | NaN | 남자 | 25827594.0 | 1877127.0 | 1682988.0 | 1806754 | 2045265.0 | 1072395.0 | 806680.0 | 600607 | 319391.0 | 113221.0 | 32695.0 | 7658 | 4137.0 |
2 | NaN | NaN | 여자 | 25868622.0 | 1663934.0 | 1534379.0 | 1711114 | 1971007.0 | 1164950.0 | 974549.0 | 857283 | 589739.0 | 302943.0 | 108793.0 | 27186 | 13425.0 |
3 | 서울특별시 | 소계 | 합계 | 9930616.0 | 690728.0 | 751973.0 | 803507 | 817467.0 | 448956.0 | 350580.0 | 251961 | 141649.0 | 66067.0 | 24153.0 | 7058 | 5475.0 |
4 | NaN | NaN | 남자 | 4876789.0 | 347534.0 | 372249.0 | 402358 | 410076.0 | 211568.0 | 163766.0 | 112076 | 54033.0 | 19595.0 | 6146.0 | 1900 | 1406.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
841 | NaN | NaN | 남자 | 235977.0 | 17377.0 | 13118.0 | 15084 | 18350.0 | 8474.0 | 6782.0 | 4941 | 2737.0 | 854.0 | 226.0 | 53 | 17.0 |
842 | NaN | NaN | 여자 | 234688.0 | 15261.0 | 12245.0 | 14687 | 18062.0 | 9265.0 | 7877.0 | 7178 | 5649.0 | 3122.0 | 1387.0 | 460 | 137.0 |
843 | NaN | 서귀포시 | 합계 | 170932.0 | 10505.0 | 8067.0 | 9120 | 11606.0 | 8686.0 | 7460.0 | 6456 | 4521.0 | 1855.0 | 733.0 | 242 | 77.0 |
844 | NaN | NaN | 남자 | 86568.0 | 5600.0 | 4247.0 | 4693 | 6082.0 | 4237.0 | 3441.0 | 2611 | 1494.0 | 370.0 | 103.0 | 29 | 9.0 |
845 | NaN | NaN | 여자 | 84364.0 | 4905.0 | 3820.0 | 4427 | 5524.0 | 4449.0 | 4019.0 | 3845 | 3027.0 | 1485.0 | 630.0 | 213 | 68.0 |
846 rows × 16 columns
In [4]:
# 결측값을 앞 방향 혹은 뒷 방향으로 채우기 # fillna(method='ffill' or 'pad'), fillna(method='bfill' or 'backfill') population.fillna(method='pad', inplace=True) population.rename(columns = {'행정구역(동읍면)별(1)':'광역시도', '행정구역(동읍면)별(2)':'시도', '계':'인구수'}, inplace=True) population = population[(population['시도'] != '소계')] population
Out[4]:
광역시도 | 시도 | 구분 | 인구수 | 20 - 24세 | 25 - 29세 | 30 - 34세 | 35 - 39세 | 65 - 69세 | 70 - 74세 | 75 - 79세 | 80 - 84세 | 85 - 89세 | 90 - 94세 | 95 - 99세 | 100+ | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
6 | 서울특별시 | 종로구 | 합계 | 152737.0 | 11379.0 | 11891.0 | 10684 | 10379.0 | 7411.0 | 6636.0 | 5263 | 3104.0 | 1480.0 | 602.0 | 234 | 220.0 |
7 | 서울특별시 | 종로구 | 남자 | 75201.0 | 5620.0 | 6181.0 | 5387 | 5034.0 | 3411.0 | 3009.0 | 2311 | 1289.0 | 506.0 | 207.0 | 89 | 73.0 |
8 | 서울특별시 | 종로구 | 여자 | 77536.0 | 5759.0 | 5710.0 | 5297 | 5345.0 | 4000.0 | 3627.0 | 2952 | 1815.0 | 974.0 | 395.0 | 145 | 147.0 |
9 | 서울특별시 | 중구 | 합계 | 125249.0 | 8216.0 | 9529.0 | 10332 | 10107.0 | 6399.0 | 5313.0 | 4127 | 2502.0 | 1260.0 | 469.0 | 158 | 160.0 |
10 | 서울특별시 | 중구 | 남자 | 62204.0 | 4142.0 | 4792.0 | 5192 | 5221.0 | 3113.0 | 2405.0 | 1752 | 929.0 | 414.0 | 132.0 | 56 | 51.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
841 | 제주특별자치도 | 제주시 | 남자 | 235977.0 | 17377.0 | 13118.0 | 15084 | 18350.0 | 8474.0 | 6782.0 | 4941 | 2737.0 | 854.0 | 226.0 | 53 | 17.0 |
842 | 제주특별자치도 | 제주시 | 여자 | 234688.0 | 15261.0 | 12245.0 | 14687 | 18062.0 | 9265.0 | 7877.0 | 7178 | 5649.0 | 3122.0 | 1387.0 | 460 | 137.0 |
843 | 제주특별자치도 | 서귀포시 | 합계 | 170932.0 | 10505.0 | 8067.0 | 9120 | 11606.0 | 8686.0 | 7460.0 | 6456 | 4521.0 | 1855.0 | 733.0 | 242 | 77.0 |
844 | 제주특별자치도 | 서귀포시 | 남자 | 86568.0 | 5600.0 | 4247.0 | 4693 | 6082.0 | 4237.0 | 3441.0 | 2611 | 1494.0 | 370.0 | 103.0 | 29 | 9.0 |
845 | 제주특별자치도 | 서귀포시 | 여자 | 84364.0 | 4905.0 | 3820.0 | 4427 | 5524.0 | 4449.0 | 4019.0 | 3845 | 3027.0 | 1485.0 | 630.0 | 213 | 68.0 |
792 rows × 16 columns
- 위 표를 보면 항목이라는 컬럼의 내용이 각 행정구역 마다 총인구수, 남자인구수, 여자인구수로 나눠있는 것을 알 수 있음
- 이를 지금 정리하기 위해 간단히 반복문(for)으로 합계, 남자, 여자로 변경하고 구분이라는 컬럼으로 저장함
- 그리고, 항목을 지우기로 함
인구 소멸 위기 지역 계산하고 데이터 정리하기¶
In [5]:
population['20-39세'] = population['20 - 24세'] + population['25 - 29세'] + \ population['30 - 34세'] + population['35 - 39세'] population['65세이상'] = population['65 - 69세'] + population['70 - 74세'] + \ population['75 - 79세'] + population['80 - 84세'] + \ population['85 - 89세'] + population['90 - 94세'] + \ population['95 - 99세'] + population['100+'] population.head()
Out[5]:
광역시도 | 시도 | 구분 | 인구수 | 20 - 24세 | 25 - 29세 | 30 - 34세 | 35 - 39세 | 65 - 69세 | 70 - 74세 | 75 - 79세 | 80 - 84세 | 85 - 89세 | 90 - 94세 | 95 - 99세 | 100+ | 20-39세 | 65세이상 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
6 | 서울특별시 | 종로구 | 합계 | 152737.0 | 11379.0 | 11891.0 | 10684 | 10379.0 | 7411.0 | 6636.0 | 5263 | 3104.0 | 1480.0 | 602.0 | 234 | 220.0 | 44333.0 | 24950.0 |
7 | 서울특별시 | 종로구 | 남자 | 75201.0 | 5620.0 | 6181.0 | 5387 | 5034.0 | 3411.0 | 3009.0 | 2311 | 1289.0 | 506.0 | 207.0 | 89 | 73.0 | 22222.0 | 10895.0 |
8 | 서울특별시 | 종로구 | 여자 | 77536.0 | 5759.0 | 5710.0 | 5297 | 5345.0 | 4000.0 | 3627.0 | 2952 | 1815.0 | 974.0 | 395.0 | 145 | 147.0 | 22111.0 | 14055.0 |
9 | 서울특별시 | 중구 | 합계 | 125249.0 | 8216.0 | 9529.0 | 10332 | 10107.0 | 6399.0 | 5313.0 | 4127 | 2502.0 | 1260.0 | 469.0 | 158 | 160.0 | 38184.0 | 20388.0 |
10 | 서울특별시 | 중구 | 남자 | 62204.0 | 4142.0 | 4792.0 | 5192 | 5221.0 | 3113.0 | 2405.0 | 1752 | 929.0 | 414.0 | 132.0 | 56 | 51.0 | 19347.0 | 8852.0 |
- pivot_table을 이용하여 광역시도,시도를 index로 두고, 구분으로 세로를 첫 번째 컬럼을 잡고, value에 인구수, 20~39세, 65세 이상으로 정리해 둔다.
In [6]:
pop = pd.pivot_table(population, index = ['광역시도', '시도'], columns = ['구분'], values = ['인구수', '20-39세', '65세이상']) pop
Out[6]:
20-39세 | 65세이상 | 인구수 | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
구분 | 남자 | 여자 | 합계 | 남자 | 여자 | 합계 | 남자 | 여자 | 합계 | |
광역시도 | 시도 | |||||||||
강원도 | 강릉시 | 26286.0 | 23098.0 | 49384.0 | 15767.0 | 21912.0 | 37679.0 | 106231.0 | 107615.0 | 213846.0 |
고성군 | 4494.0 | 2529.0 | 7023.0 | 2900.0 | 4251.0 | 7151.0 | 15899.0 | 14215.0 | 30114.0 | |
동해시 | 11511.0 | 9753.0 | 21264.0 | 6392.0 | 8732.0 | 15124.0 | 47166.0 | 46131.0 | 93297.0 | |
삼척시 | 8708.0 | 7115.0 | 15823.0 | 5892.0 | 8718.0 | 14610.0 | 35253.0 | 34346.0 | 69599.0 | |
속초시 | 9956.0 | 8752.0 | 18708.0 | 5139.0 | 7613.0 | 12752.0 | 40288.0 | 41505.0 | 81793.0 | |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
충청북도 | 진천군 | 9391.0 | 7622.0 | 17013.0 | 4731.0 | 6575.0 | 11306.0 | 36387.0 | 33563.0 | 69950.0 |
청원구 | 32216.0 | 27805.0 | 60021.0 | 8417.0 | 11914.0 | 20331.0 | 97006.0 | 93807.0 | 190813.0 | |
청주시 | 128318.0 | 115719.0 | 244037.0 | 37882.0 | 53671.0 | 91553.0 | 419323.0 | 415874.0 | 835197.0 | |
충주시 | 26600.0 | 22757.0 | 49357.0 | 14407.0 | 20383.0 | 34790.0 | 104877.0 | 103473.0 | 208350.0 | |
흥덕구 | 40933.0 | 37675.0 | 78608.0 | 9788.0 | 13671.0 | 23459.0 | 127647.0 | 125916.0 | 253563.0 |
264 rows × 9 columns
- 소멸비율이라는 컬럼에 인구소멸위기지역을 계산하기 위한 식을 적용한다
- 이 비율이 1보다 작으면 인구소멸위기지역으로 볼 수 있다.
In [7]:
pop['소멸비율'] = pop['20-39세','여자'] / (pop['65세이상','합계'] / 2) pop.head()
Out[7]:
20-39세 | 65세이상 | 인구수 | 소멸비율 | ||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
구분 | 남자 | 여자 | 합계 | 남자 | 여자 | 합계 | 남자 | 여자 | 합계 | ||
광역시도 | 시도 | ||||||||||
강원도 | 강릉시 | 26286.0 | 23098.0 | 49384.0 | 15767.0 | 21912.0 | 37679.0 | 106231.0 | 107615.0 | 213846.0 | 1.226041 |
고성군 | 4494.0 | 2529.0 | 7023.0 | 2900.0 | 4251.0 | 7151.0 | 15899.0 | 14215.0 | 30114.0 | 0.707314 | |
동해시 | 11511.0 | 9753.0 | 21264.0 | 6392.0 | 8732.0 | 15124.0 | 47166.0 | 46131.0 | 93297.0 | 1.289738 | |
삼척시 | 8708.0 | 7115.0 | 15823.0 | 5892.0 | 8718.0 | 14610.0 | 35253.0 | 34346.0 | 69599.0 | 0.973990 | |
속초시 | 9956.0 | 8752.0 | 18708.0 | 5139.0 | 7613.0 | 12752.0 | 40288.0 | 41505.0 | 81793.0 | 1.372647 |
- 소멸위기지역인지를 boolean으로 지정해 둔다
In [8]:
pop['소멸위기지역'] = pop['소멸비율'] < 1.0 pop.head()
Out[8]:
20-39세 | 65세이상 | 인구수 | 소멸비율 | 소멸위기지역 | ||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
구분 | 남자 | 여자 | 합계 | 남자 | 여자 | 합계 | 남자 | 여자 | 합계 | |||
광역시도 | 시도 | |||||||||||
강원도 | 강릉시 | 26286.0 | 23098.0 | 49384.0 | 15767.0 | 21912.0 | 37679.0 | 106231.0 | 107615.0 | 213846.0 | 1.226041 | False |
고성군 | 4494.0 | 2529.0 | 7023.0 | 2900.0 | 4251.0 | 7151.0 | 15899.0 | 14215.0 | 30114.0 | 0.707314 | True | |
동해시 | 11511.0 | 9753.0 | 21264.0 | 6392.0 | 8732.0 | 15124.0 | 47166.0 | 46131.0 | 93297.0 | 1.289738 | False | |
삼척시 | 8708.0 | 7115.0 | 15823.0 | 5892.0 | 8718.0 | 14610.0 | 35253.0 | 34346.0 | 69599.0 | 0.973990 | True | |
속초시 | 9956.0 | 8752.0 | 18708.0 | 5139.0 | 7613.0 | 12752.0 | 40288.0 | 41505.0 | 81793.0 | 1.372647 | False |
In [9]:
#다중색인 #df.index.get_level_values('name_index') pop[pop['소멸위기지역']==True].index.get_level_values(0)
Out[9]:
Index(['강원도', '강원도', '강원도', '강원도', '강원도', '강원도', '강원도', '강원도', '경기도', '경기도', '경기도', '경상남도', '경상남도', '경상남도', '경상남도', '경상남도', '경상남도', '경상남도', '경상남도', '경상남도', '경상남도', '경상남도', '경상북도', '경상북도', '경상북도', '경상북도', '경상북도', '경상북도', '경상북도', '경상북도', '경상북도', '경상북도', '경상북도', '경상북도', '경상북도', '경상북도', '경상북도', '경상북도', '부산광역시', '부산광역시', '인천광역시', '인천광역시', '전라남도', '전라남도', '전라남도', '전라남도', '전라남도', '전라남도', '전라남도', '전라남도', '전라남도', '전라남도', '전라남도', '전라남도', '전라남도', '전라남도', '전라남도', '전라남도', '전라북도', '전라북도', '전라북도', '전라북도', '전라북도', '전라북도', '전라북도', '전라북도', '전라북도', '전라북도', '충청남도', '충청남도', '충청남도', '충청남도', '충청남도', '충청남도', '충청남도', '충청남도', '충청남도', '충청남도', '충청북도', '충청북도', '충청북도', '충청북도', '충청북도'], dtype='object', name='광역시도')
In [10]:
pop[pop['소멸위기지역']==True].index.get_level_values(1)
Out[10]:
Index(['고성군', '삼척시', '양양군', '영월군', '정선군', '평창군', '홍천군', '횡성군', '가평군', '양평군', '연천군', '거창군', '고성군', '남해군', '밀양시', '산청군', '의령군', '창녕군', '하동군', '함안군', '함양군', '합천군', '고령군', '군위군', '문경시', '봉화군', '상주시', '성주군', '영덕군', '영양군', '영주시', '영천시', '예천군', '울릉군', '울진군', '의성군', '청도군', '청송군', '동구', '영도구', '강화군', '옹진군', '강진군', '고흥군', '곡성군', '구례군', '담양군', '보성군', '신안군', '영광군', '영암군', '완도군', '장성군', '장흥군', '진도군', '함평군', '해남군', '화순군', '고창군', '김제시', '남원시', '무주군', '부안군', '순창군', '임실군', '장수군', '정읍시', '진안군', '공주시', '금산군', '논산시', '보령시', '부여군', '서천군', '예산군', '청양군', '태안군', '홍성군', '괴산군', '단양군', '보은군', '영동군', '옥천군'], dtype='object', name='시도')
- pivot_table로 잘정리가 된 상태에서 .reset_index로 pivot_table의 reset 속성을 다시 설정한다.
In [11]:
pop.reset_index(inplace=True) pop.head()
Out[11]:
광역시도 | 시도 | 20-39세 | 65세이상 | 인구수 | 소멸비율 | 소멸위기지역 | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
구분 | 남자 | 여자 | 합계 | 남자 | 여자 | 합계 | 남자 | 여자 | 합계 | ||||
0 | 강원도 | 강릉시 | 26286.0 | 23098.0 | 49384.0 | 15767.0 | 21912.0 | 37679.0 | 106231.0 | 107615.0 | 213846.0 | 1.226041 | False |
1 | 강원도 | 고성군 | 4494.0 | 2529.0 | 7023.0 | 2900.0 | 4251.0 | 7151.0 | 15899.0 | 14215.0 | 30114.0 | 0.707314 | True |
2 | 강원도 | 동해시 | 11511.0 | 9753.0 | 21264.0 | 6392.0 | 8732.0 | 15124.0 | 47166.0 | 46131.0 | 93297.0 | 1.289738 | False |
3 | 강원도 | 삼척시 | 8708.0 | 7115.0 | 15823.0 | 5892.0 | 8718.0 | 14610.0 | 35253.0 | 34346.0 | 69599.0 | 0.973990 | True |
4 | 강원도 | 속초시 | 9956.0 | 8752.0 | 18708.0 | 5139.0 | 7613.0 | 12752.0 | 40288.0 | 41505.0 | 81793.0 | 1.372647 | False |
In [12]:
print(pop.columns.get_level_values(0)) print(pop.columns.get_level_values(1))
Index(['광역시도', '시도', '20-39세', '20-39세', '20-39세', '65세이상', '65세이상', '65세이상', '인구수', '인구수', '인구수', '소멸비율', '소멸위기지역'], dtype='object') Index(['', '', '남자', '여자', '합계', '남자', '여자', '합계', '남자', '여자', '합계', '', ''], dtype='object', name='구분')
- 이중 columns을 해제하기 위해 두컬럼 제목을 합쳐 다시 지정한다.
In [13]:
tmp_coloumns = [pop.columns.get_level_values(0)[n] + \ pop.columns.get_level_values(1)[n] for n in range(0,len(pop.columns.get_level_values(0)))] pop.columns = tmp_coloumns pop.head()
Out[13]:
광역시도 | 시도 | 20-39세남자 | 20-39세여자 | 20-39세합계 | 65세이상남자 | 65세이상여자 | 65세이상합계 | 인구수남자 | 인구수여자 | 인구수합계 | 소멸비율 | 소멸위기지역 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 강원도 | 강릉시 | 26286.0 | 23098.0 | 49384.0 | 15767.0 | 21912.0 | 37679.0 | 106231.0 | 107615.0 | 213846.0 | 1.226041 | False |
1 | 강원도 | 고성군 | 4494.0 | 2529.0 | 7023.0 | 2900.0 | 4251.0 | 7151.0 | 15899.0 | 14215.0 | 30114.0 | 0.707314 | True |
2 | 강원도 | 동해시 | 11511.0 | 9753.0 | 21264.0 | 6392.0 | 8732.0 | 15124.0 | 47166.0 | 46131.0 | 93297.0 | 1.289738 | False |
3 | 강원도 | 삼척시 | 8708.0 | 7115.0 | 15823.0 | 5892.0 | 8718.0 | 14610.0 | 35253.0 | 34346.0 | 69599.0 | 0.973990 | True |
4 | 강원도 | 속초시 | 9956.0 | 8752.0 | 18708.0 | 5139.0 | 7613.0 | 12752.0 | 40288.0 | 41505.0 | 81793.0 | 1.372647 | False |
지도 시각화를 위해 지역별 고유 ID 만들기¶
In [14]:
pop['시도'].unique()
Out[14]:
array(['강릉시', '고성군', '동해시', '삼척시', '속초시', '양구군', '양양군', '영월군', '원주시', '인제군', '정선군', '철원군', '춘천시', '태백시', '평창군', '홍천군', '화천군', '횡성군', '가평군', '고양시', '과천시', '광명시', '광주시', '구리시', '군포시', '권선구', '기흥구', '김포시', '남양주시', '단원구', '덕양구', '동두천시', '동안구', '만안구', '부천시', '분당구', '상록구', '성남시', '소사구', '수원시', '수정구', '수지구', '시흥시', '안산시', '안성시', '안양시', '양주시', '양평군', '여주시', '연천군', '영통구', '오산시', '오정구', '용인시', '원미구', '의왕시', '의정부시', '이천시', '일산동구', '일산서구', '장안구', '중원구', '처인구', '파주시', '팔달구', '평택시', '포천시', '하남시', '화성시', '거제시', '거창군', '김해시', '남해군', '마산합포구', '마산회원구', '밀양시', '사천시', '산청군', '성산구', '양산시', '의령군', '의창구', '진주시', '진해구', '창녕군', '창원시', '통영시', '하동군', '함안군', '함양군', '합천군', '경산시', '경주시', '고령군', '구미시', '군위군', '김천시', '남구', '문경시', '봉화군', '북구', '상주시', '성주군', '안동시', '영덕군', '영양군', '영주시', '영천시', '예천군', '울릉군', '울진군', '의성군', '청도군', '청송군', '칠곡군', '포항시', '광산구', '동구', '서구', '달서구', '달성군', '수성구', '중구', '대덕구', '유성구', '강서구', '금정구', '기장군', '동래구', '부산진구', '사상구', '사하구', '수영구', '연제구', '영도구', '해운대구', '강남구', '강동구', '강북구', '관악구', '광진구', '구로구', '금천구', '노원구', '도봉구', '동대문구', '동작구', '마포구', '서대문구', '서초구', '성동구', '성북구', '송파구', '양천구', '영등포구', '용산구', '은평구', '종로구', '중랑구', '세종특별자치시', '울주군', '강화군', '계양구', '남동구', '부평구', '연수구', '옹진군', '강진군', '고흥군', '곡성군', '광양시', '구례군', '나주시', '담양군', '목포시', '무안군', '보성군', '순천시', '신안군', '여수시', '영광군', '영암군', '완도군', '장성군', '장흥군', '진도군', '함평군', '해남군', '화순군', '고창군', '군산시', '김제시', '남원시', '덕진구', '무주군', '부안군', '순창군', '완산구', '완주군', '익산시', '임실군', '장수군', '전주시', '정읍시', '진안군', '서귀포시', '제주시', '계룡시', '공주시', '금산군', '논산시', '당진시', '동남구', '보령시', '부여군', '서북구', '서산시', '서천군', '아산시', '예산군', '천안시', '청양군', '태안군', '홍성군', '괴산군', '단양군', '보은군', '상당구', '서원구', '영동군', '옥천군', '음성군', '제천시', '증평군', '진천군', '청원구', '청주시', '충주시', '흥덕구'], dtype=object)
In [15]:
# 인천, 부산등 광역시 > 자치구 # 안양시, 수원시 > 행정구 pop[pop['시도'] == '분당구']
Out[15]:
광역시도 | 시도 | 20-39세남자 | 20-39세여자 | 20-39세합계 | 65세이상남자 | 65세이상여자 | 65세이상합계 | 인구수남자 | 인구수여자 | 인구수합계 | 소멸비율 | 소멸위기지역 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
35 | 경기도 | 분당구 | 72407.0 | 77174.0 | 149581.0 | 21745.0 | 29118.0 | 50863.0 | 244502.0 | 259328.0 | 503830.0 | 3.034583 | False |
In [16]:
si_name = [None] * len(pop) tmp_gu_dict = {'수원':['장안구', '권선구', '팔달구', '영통구'], '성남':['수정구', '중원구', '분당구'], '안양':['만안구', '동안구'], '안산':['상록구', '단원구'], '고양':['덕양구', '일산동구', '일산서구'], '용인':['처인구', '기흥구', '수지구'], '청주':['상당구', '서원구', '흥덕구', '청원구'], '천안':['동남구', '서북구'], '전주':['완산구', '덕진구'], '포항':['남구', '북구'], '창원':['의창구', '성산구', '진해구', '마산합포구', '마산회원구'], '부천':['오정구', '원미구', '소사구']}
In [17]:
for n in pop.index: if pop['광역시도'][n][-3:] not in ['광역시', '특별시', '자치시']: if pop['시도'][n][:-1]=='고성' and pop['광역시도'][n]=='강원도': si_name[n] = '고성(강원)' elif pop['시도'][n][:-1]=='고성' and pop['광역시도'][n]=='경상남도': si_name[n] = '고성(경남)' else: si_name[n] = pop['시도'][n][:-1] for keys, values in tmp_gu_dict.items(): if pop['시도'][n] in values: #keys values if len(pop['시도'][n])==2: #'포항':['남구','북구'] si_name[n] = keys + ' ' + pop['시도'][n] # 포항 남구 elif pop['시도'][n] in ['마산합포구','마산회원구']: # '창원':['마산합포구','마산회원구'] si_name[n] = keys + ' ' + pop['시도'][n][2:-1] # 창원 합포 else: # '안양':['만안구', '동안구'] si_name[n] = keys + ' ' + pop['시도'][n][:-1] # 안양 만안 elif pop['광역시도'][n] == '세종특별자치시': si_name[n] = '세종' else: if len(pop['시도'][n])==2: #서울특별시 중구 si_name[n] = pop['광역시도'][n][:2] + ' ' + pop['시도'][n] # 서울 중구 else: si_name[n] = pop['광역시도'][n][:2] + ' ' + pop['시도'][n][:-1] # 서울 구로
In [18]:
si_name
Out[18]:
['강릉', '고성(강원)', '동해', '삼척', '속초', '양구', '양양', '영월', '원주', '인제', '정선', '철원', '춘천', '태백', '평창', '홍천', '화천', '횡성', '가평', '고양', '과천', '광명', '광주', '구리', '군포', '수원 권선', '용인 기흥', '김포', '남양주', '안산 단원', '고양 덕양', '동두천', '안양 동안', '안양 만안', '부천', '성남 분당', '안산 상록', '성남', '부천 소사', '수원', '성남 수정', '용인 수지', '시흥', '안산', '안성', '안양', '양주', '양평', '여주', '연천', '수원 영통', '오산', '부천 오정', '용인', '부천 원미', '의왕', '의정부', '이천', '고양 일산동', '고양 일산서', '수원 장안', '성남 중원', '용인 처인', '파주', '수원 팔달', '평택', '포천', '하남', '화성', '거제', '거창', '고성(경남)', '김해', '남해', '창원 합포', '창원 회원', '밀양', '사천', '산청', '창원 성산', '양산', '의령', '창원 의창', '진주', '창원 진해', '창녕', '창원', '통영', '하동', '함안', '함양', '합천', '경산', '경주', '고령', '구미', '군위', '김천', '포항 남구', '문경', '봉화', '포항 북구', '상주', '성주', '안동', '영덕', '영양', '영주', '영천', '예천', '울릉', '울진', '의성', '청도', '청송', '칠곡', '포항', '광주 광산', '광주 남구', '광주 동구', '광주 북구', '광주 서구', '대구 남구', '대구 달서', '대구 달성', '대구 동구', '대구 북구', '대구 서구', '대구 수성', '대구 중구', '대전 대덕', '대전 동구', '대전 서구', '대전 유성', '대전 중구', '부산 강서', '부산 금정', '부산 기장', '부산 남구', '부산 동구', '부산 동래', '부산 부산진', '부산 북구', '부산 사상', '부산 사하', '부산 서구', '부산 수영', '부산 연제', '부산 영도', '부산 중구', '부산 해운대', '서울 강남', '서울 강동', '서울 강북', '서울 강서', '서울 관악', '서울 광진', '서울 구로', '서울 금천', '서울 노원', '서울 도봉', '서울 동대문', '서울 동작', '서울 마포', '서울 서대문', '서울 서초', '서울 성동', '서울 성북', '서울 송파', '서울 양천', '서울 영등포', '서울 용산', '서울 은평', '서울 종로', '서울 중구', '서울 중랑', '세종', '울산 남구', '울산 동구', '울산 북구', '울산 울주', '울산 중구', '인천 강화', '인천 계양', '인천 남구', '인천 남동', '인천 동구', '인천 부평', '인천 서구', '인천 연수', '인천 옹진', '인천 중구', '강진', '고흥', '곡성', '광양', '구례', '나주', '담양', '목포', '무안', '보성', '순천', '신안', '여수', '영광', '영암', '완도', '장성', '장흥', '진도', '함평', '해남', '화순', '고창', '군산', '김제', '남원', '전주 덕진', '무주', '부안', '순창', '전주 완산', '완주', '익산', '임실', '장수', '전주', '정읍', '진안', '서귀포', '제주', '계룡', '공주', '금산', '논산', '당진', '천안 동남', '보령', '부여', '천안 서북', '서산', '서천', '아산', '예산', '천안', '청양', '태안', '홍성', '괴산', '단양', '보은', '청주 상당', '청주 서원', '영동', '옥천', '음성', '제천', '증평', '진천', '청주 청원', '청주', '충주', '청주 흥덕']
- 지도 시각화에 사용하기 위해 위과정에서 만들어진 행정구역의 고유한 이름을 ID로 지정한다
In [19]:
pop['ID'] = si_name
In [20]:
del pop['20-39세남자'] del pop['65세이상남자'] del pop['65세이상여자'] pop.head()
Out[20]:
광역시도 | 시도 | 20-39세여자 | 20-39세합계 | 65세이상합계 | 인구수남자 | 인구수여자 | 인구수합계 | 소멸비율 | 소멸위기지역 | ID | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 강원도 | 강릉시 | 23098.0 | 49384.0 | 37679.0 | 106231.0 | 107615.0 | 213846.0 | 1.226041 | False | 강릉 |
1 | 강원도 | 고성군 | 2529.0 | 7023.0 | 7151.0 | 15899.0 | 14215.0 | 30114.0 | 0.707314 | True | 고성(강원) |
2 | 강원도 | 동해시 | 9753.0 | 21264.0 | 15124.0 | 47166.0 | 46131.0 | 93297.0 | 1.289738 | False | 동해 |
3 | 강원도 | 삼척시 | 7115.0 | 15823.0 | 14610.0 | 35253.0 | 34346.0 | 69599.0 | 0.973990 | True | 삼척 |
4 | 강원도 | 속초시 | 8752.0 | 18708.0 | 12752.0 | 40288.0 | 41505.0 | 81793.0 | 1.372647 | False | 속초 |
Cartogram으로 우리나라 지도 만들기¶
In [21]:
draw_korea_raw = pd.read_excel('../../data/05. draw_korea_raw.xlsx') draw_korea_raw
Out[21]:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 철원 | 화천 | 양구 | 고성(강원) | NaN | NaN | NaN |
1 | NaN | NaN | NaN | 양주 | 동두천 | 연천 | 포천 | 의정부 | 인제 | 춘천 | 속초 | NaN | NaN | NaN |
2 | NaN | NaN | NaN | 고양 덕양 | 고양 일산동 | 서울 도봉 | 서울 노원 | 남양주 | 홍천 | 횡성 | 양양 | NaN | NaN | NaN |
3 | NaN | NaN | 파주 | 고양 일산서 | 김포 | 서울 강북 | 서울 성북 | 가평 | 구리 | 하남 | 정선 | 강릉 | NaN | NaN |
4 | NaN | NaN | 부천 소사 | 안양 만안 | 광명 | 서울 서대문 | 서울 종로 | 서울 동대문 | 서울 중랑 | 양평 | 태백 | 동해 | NaN | NaN |
5 | NaN | 인천 강화 | 부천 원미 | 안양 동안 | 서울 은평 | 서울 마포 | 서울 중구 | 서울 성동 | 서울 강동 | 여주 | 원주 | 삼척 | NaN | NaN |
6 | NaN | 인천 서구 | 부천 오정 | 시흥 | 서울 강서 | 서울 동작 | 서울 용산 | 서울 광진 | 서울 송파 | 이천 | 평창 | 울진 | NaN | NaN |
7 | NaN | 인천 동구 | 인천 계양 | 안산 상록 | 서울 양천 | 서울 관악 | 서울 서초 | 성남 중원 | 과천 | 광주 | 영월 | 영덕 | NaN | NaN |
8 | NaN | NaN | 인천 부평 | 안산 단원 | 서울 영등포 | 서울 금천 | 서울 강남 | 성남 분당 | 성남 수정 | 용인 수지 | 문경 | 봉화 | NaN | 울릉 |
9 | NaN | 인천 중구 | 인천 남구 | 화성 | 서울 구로 | 군포 | 의왕 | 수원 영통 | 용인 기흥 | 용인 처인 | 안동 | 영양 | NaN | NaN |
10 | 인천 옹진 | 인천 연수 | 인천 남동 | 오산 | 안성 | 수원 권선 | 수원 장안 | 제천 | 예천 | 영주 | 구미 | 청송 | 포항 북구 | NaN |
11 | 태안 | 아산 | 천안 동남 | 천안 서북 | 평택 | 음성 | 수원 팔달 | 단양 | 상주 | 김천 | 군위 | 의성 | 포항 남구 | NaN |
12 | NaN | 당진 | 홍성 | 예산 | 공주 | 진천 | 충주 | 청주 흥덕 | 괴산 | 칠곡 | 영천 | 경산 | 경주 | NaN |
13 | NaN | 서산 | 보령 | 청양 | 세종 | 대전 대덕 | 증평 | 청주 청원 | 보은 | 고령 | 청도 | 성주 | 울산 북구 | NaN |
14 | NaN | NaN | 부여 | 논산 | 계룡 | 대전 동구 | 청주 상당 | 청주 서원 | 대구 북구 | 대구 중구 | 대구 수성 | 울산 울주 | 울산 동구 | NaN |
15 | NaN | NaN | 서천 | 금산 | 대전 유성 | 대전 중구 | 옥천 | 영동 | 대구 서구 | 대구 남구 | 대구 동구 | 울산 중구 | 울산 남구 | NaN |
16 | NaN | NaN | 군산 | 익산 | 대전 서구 | 무주 | 거창 | 합천 | 대구 달서 | 대구 달성 | 부산 금정 | 부산 동래 | 부산 기장 | NaN |
17 | NaN | NaN | 부안 | 김제 | 완주 | 장수 | 함양 | 창녕 | 밀양 | 부산 북구 | 부산 부산진 | 부산 연제 | 부산 해운대 | NaN |
18 | NaN | 고창 | 정읍 | 전주 덕진 | 진안 | 남원 | 진주 | 의령 | 부산 강서 | 부산 사상 | 부산 동구 | 부산 중구 | NaN | NaN |
19 | NaN | 영광 | 장성 | 전주 완산 | 임실 | 산청 | 함안 | 양산 | 창원 합포 | 부산 서구 | 부산 사하 | 부산 남구 | NaN | NaN |
20 | NaN | 함평 | 담양 | 순창 | 구례 | 하동 | 창원 의창 | 창원 성산 | 창원 진해 | 김해 | 부산 영도 | 부산 수영 | NaN | NaN |
21 | 신안 | 무안 | 광주 광산 | 곡성 | 화순 | 광양 | 사천 | 창원 회원 | 통영 | NaN | NaN | NaN | NaN | NaN |
22 | 목포 | 나주 | 광주 서구 | 광주 북구 | 순천 | 고흥 | 남해 | 고성(경남) | 거제 | NaN | NaN | NaN | NaN | NaN |
23 | 해남 | 영암 | 광주 남구 | 광주 동구 | 여수 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
24 | 진도 | 강진 | 장흥 | 보성 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
25 | NaN | NaN | 완도 | NaN | NaN | 제주 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
26 | NaN | NaN | NaN | NaN | NaN | 서귀포 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
- 이제 각 행정구역의 화면상 좌표를 얻기위해 pivot_table의 반대개념으로 .stack() 명령을 사용한다.
In [22]:
draw_korea_raw_stacked = pd.DataFrame(draw_korea_raw.stack()) draw_korea_raw_stacked.reset_index(inplace=True) draw_korea_raw_stacked.rename(columns={'level_0':'y', 'level_1':'x', 0:'ID'}, inplace=True) draw_korea_raw_stacked
Out[22]:
y | x | ID | |
---|---|---|---|
0 | 0 | 7 | 철원 |
1 | 0 | 8 | 화천 |
2 | 0 | 9 | 양구 |
3 | 0 | 10 | 고성(강원) |
4 | 1 | 3 | 양주 |
... | ... | ... | ... |
247 | 24 | 2 | 장흥 |
248 | 24 | 3 | 보성 |
249 | 25 | 2 | 완도 |
250 | 25 | 5 | 제주 |
251 | 26 | 5 | 서귀포 |
252 rows × 3 columns
- 다시 인덱스를 재설정하고
- 컬럼의 이름을 다시 설정해 준다.
In [23]:
draw_korea = draw_korea_raw_stacked
- 먼저 ID 컬럼에서 시도에 표기할때 시 이름 구 이름으로 줄을 나누기 위해 분리한다
In [24]:
BORDER_LINES = [ [(5, 1), (5,2), (7,2), (7,3), (11,3), (11,0)], # 인천 [(5,4), (5,5), (2,5), (2,7), (4,7), (4,9), (7,9), (7,7), (9,7), (9,5), (10,5), (10,4), (5,4)], # 서울 [(1,7), (1,8), (3,8), (3,10), (10,10), (10,7), (12,7), (12,6), (11,6), (11,5), (12, 5), (12,4), (11,4), (11,3)], # 경기도 [(8,10), (8,11), (6,11), (6,12)], # 강원도 [(12,5), (13,5), (13,4), (14,4), (14,5), (15,5), (15,4), (16,4), (16,2)], # 충청북도 [(16,4), (17,4), (17,5), (16,5), (16,6), (19,6), (19,5), (20,5), (20,4), (21,4), (21,3), (19,3), (19,1)], # 전라북도 [(13,5), (13,6), (16,6)], # 대전시 [(13,5), (14,5)], #세종시 [(21,2), (21,3), (22,3), (22,4), (24,4), (24,2), (21,2)], #광주 [(20,5), (21,5), (21,6), (23,6)], #전라남도 [(10,8), (12,8), (12,9), (14,9), (14,8), (16,8), (16,6)], #충청북도 [(14,9), (14,11), (14,12), (13,12), (13,13)], #경상북도 [(15,8), (17,8), (17,10), (16,10), (16,11), (14,11)], #대구 [(17,9), (18,9), (18,8), (19,8), (19,9), (20,9), (20,10), (21,10)], #부산 [(16,11), (16,13)], #울산 # [(9,14), (9,15)], [(27,5), (27,6), (25,6)], ]
In [25]:
plt.figure(figsize=(8, 11)) # 지역 이름 표시 for idx, row in draw_korea.iterrows(): # 광역시는 구 이름이 겹치는 경우가 많아서 시단위 이름도 같이 표시한다. # (중구, 서구) if len(row['ID'].split())==2: dispname = '{}\n{}'.format(row['ID'].split()[0], row['ID'].split()[1]) elif row['ID'][:2]=='고성': dispname = '고성' else: dispname = row['ID'] # 서대문구, 서귀포시 같이 이름이 3자 이상인 경우에 작은 글자로 표시한다. if len(dispname.splitlines()[-1]) >= 3: fontsize, linespacing = 9.5, 1.5 else: fontsize, linespacing = 11, 1.2 plt.annotate(dispname, (row['x']+0.5, row['y']+0.5), weight='bold', fontsize=fontsize, ha='center', va='center', linespacing=linespacing) # 시도 경계 그린다. for path in BORDER_LINES: ys, xs = zip(*path) plt.plot(xs, ys, c='black', lw=1.5) plt.gca().invert_yaxis() #plt.gca().set_aspect(1) plt.axis('off') plt.tight_layout() plt.show()
- 인구에 대한 분석 결과인 pop과 지도를 그리기 위한 draw_korea의 데이터를 합칠 때 사용할 key인 ID컬럼의 내용이 문제가 없는지 확인하자
In [26]:
set(draw_korea['ID'].unique()) - set(pop['ID'].unique())
Out[26]:
set()
In [27]:
set(pop['ID'].unique()) - set(draw_korea['ID'].unique())
Out[27]:
{'고양', '부천', '성남', '수원', '안산', '안양', '용인', '전주', '창원', '천안', '청주', '포항'}
- 위 결과에 따르면, pop에 행정구를 가진 시들의 데이터가 더 있다는 것을 알 수 있다.
- 어차피 지도에서는 표시되지 못하니 삭제한다.
In [28]:
tmp_list = list(set(pop['ID'].unique()) - set(draw_korea['ID'].unique())) for tmp in tmp_list: pop = pop.drop(pop[pop['ID']==tmp].index) print(set(pop['ID'].unique()) - set(draw_korea['ID'].unique()))
set()
- 이제 pop과 draw_korea의 ID컬럼이 일치했다고 보고, ID를 key로 merge를 시키도록한다.
In [29]:
pop = pd.merge(pop, draw_korea, how='left', on=['ID']) pop.head()
Out[29]:
광역시도 | 시도 | 20-39세여자 | 20-39세합계 | 65세이상합계 | 인구수남자 | 인구수여자 | 인구수합계 | 소멸비율 | 소멸위기지역 | ID | y | x | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 강원도 | 강릉시 | 23098.0 | 49384.0 | 37679.0 | 106231.0 | 107615.0 | 213846.0 | 1.226041 | False | 강릉 | 3 | 11 |
1 | 강원도 | 고성군 | 2529.0 | 7023.0 | 7151.0 | 15899.0 | 14215.0 | 30114.0 | 0.707314 | True | 고성(강원) | 0 | 10 |
2 | 강원도 | 동해시 | 9753.0 | 21264.0 | 15124.0 | 47166.0 | 46131.0 | 93297.0 | 1.289738 | False | 동해 | 4 | 11 |
3 | 강원도 | 삼척시 | 7115.0 | 15823.0 | 14610.0 | 35253.0 | 34346.0 | 69599.0 | 0.973990 | True | 삼척 | 5 | 11 |
4 | 강원도 | 속초시 | 8752.0 | 18708.0 | 12752.0 | 40288.0 | 41505.0 | 81793.0 | 1.372647 | False | 속초 | 1 | 10 |
In [30]:
mapdata = pop.pivot_table(index='y', columns='x', values='인구수합계') masked_mapdata = np.ma.masked_where(np.isnan(mapdata), mapdata)
In [31]:
mapdata
Out[31]:
x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
y | ||||||||||||||
0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 48013.0 | 26264.0 | 24010.0 | 30114.0 | NaN | NaN | NaN |
1 | NaN | NaN | NaN | 205513.0 | 98277.0 | 45907.0 | 154763.0 | 438457.0 | 32720.0 | 280707.0 | 81793.0 | NaN | NaN | NaN |
2 | NaN | NaN | NaN | 446233.0 | 292612.0 | 348220.0 | 567581.0 | 662154.0 | 70076.0 | 45991.0 | 27218.0 | NaN | NaN | NaN |
3 | NaN | NaN | 430781.000000 | 300839.0 | 363443.0 | 327195.0 | 450355.0 | 62448.0 | 193763.0 | 211101.0 | 38718.0 | 213846.0 | NaN | NaN |
4 | NaN | NaN | 283793.333333 | 252353.0 | 339484.0 | 314194.0 | 152737.0 | 355069.0 | 411005.0 | 111367.0 | 47070.0 | 93297.0 | NaN | NaN |
5 | NaN | 68010.0 | 283793.333333 | 345061.0 | 491476.0 | 379892.0 | 125249.0 | 299259.0 | 444168.0 | 111563.0 | 337979.0 | 69599.0 | NaN | NaN |
6 | NaN | 510733.0 | 283793.333333 | 402888.0 | 595485.0 | 400997.0 | 230241.0 | 357215.0 | 657831.0 | 210359.0 | 43318.0 | 51738.0 | NaN | NaN |
7 | NaN | 71014.0 | 330284.000000 | 375857.0 | 477739.0 | 506851.0 | 447192.0 | 237909.0 | 63778.0 | 327723.0 | 40073.0 | 39052.0 | NaN | NaN |
8 | NaN | NaN | 549716.000000 | 314002.0 | 370613.0 | 235386.0 | 567115.0 | 503830.0 | 232841.0 | 347833.0 | 74702.0 | 33539.0 | NaN | 10001.0 |
9 | NaN | 115249.0 | 417103.000000 | 640890.0 | 417551.0 | 284890.0 | 156763.0 | 340654.0 | 417163.0 | 226130.0 | 168798.0 | 17713.0 | NaN | NaN |
10 | 21351.0 | 328627.0 | 530982.000000 | 208656.0 | 182896.0 | 358393.0 | 296479.0 | 136517.0 | 46166.0 | 109247.0 | 419891.0 | 26301.0 | 272027.0 | NaN |
11 | 63900.0 | 302929.0 | 258919.000000 | 359036.0 | 470832.0 | 97787.0 | 198515.0 | 30503.0 | 101799.0 | 142256.0 | 24171.0 | 54014.0 | 244748.0 | NaN |
12 | NaN | 166630.0 | 99971.000000 | 81339.0 | 109931.0 | 69950.0 | 208350.0 | 253563.0 | 38973.0 | 123199.0 | 100521.0 | 258037.0 | 259452.0 | NaN |
13 | NaN | 170788.0 | 103873.000000 | 32753.0 | 243048.0 | 192688.0 | 37308.0 | 190813.0 | 34221.0 | 34257.0 | 43564.0 | 45205.0 | 195285.0 | NaN |
14 | NaN | NaN | 70187.000000 | 123213.0 | 42634.0 | 234959.0 | 173701.0 | 217120.0 | 440383.0 | 79712.0 | 447011.0 | 219255.0 | 174514.0 | NaN |
15 | NaN | NaN | 56012.000000 | 54612.0 | 343222.0 | 252490.0 | 52267.0 | 50552.0 | 199507.0 | 156433.0 | 351352.0 | 242536.0 | 340714.0 | NaN |
16 | NaN | NaN | 277551.000000 | 300479.0 | 491011.0 | 24949.0 | 63308.0 | 48026.0 | 591891.0 | 218268.0 | 244624.0 | 272745.0 | 158527.0 | NaN |
17 | NaN | NaN | 57005.000000 | 87782.0 | 95480.0 | 23628.0 | 40241.0 | 63982.0 | 108354.0 | 310202.0 | 376526.0 | 207268.0 | 419853.0 | NaN |
18 | NaN | 60597.0 | 115173.000000 | 289899.0 | 26069.0 | 84188.0 | 346739.0 | 28111.0 | 108909.0 | 232800.0 | 89826.0 | 45208.0 | NaN | NaN |
19 | NaN | 55618.0 | 46104.000000 | 361845.0 | 30197.0 | 36098.0 | 68937.0 | 317037.0 | 181797.0 | 112973.0 | 334603.0 | 278779.0 | NaN | NaN |
20 | NaN | 34397.0 | 47229.000000 | 29949.0 | 27412.0 | 49622.0 | 252435.0 | 231571.0 | 187313.0 | 529422.0 | 126362.0 | 179324.0 | NaN | NaN |
21 | 42652.0 | 82109.0 | 403049.000000 | 30400.0 | 65303.0 | 155580.0 | 114912.0 | 210791.0 | 138160.0 | NaN | NaN | NaN | NaN | NaN |
22 | 237739.0 | 104376.0 | 309579.000000 | 441066.0 | 278548.0 | 67656.0 | 45129.0 | 54703.0 | 257183.0 | NaN | NaN | NaN | NaN | NaN |
23 | 75121.0 | 57045.0 | 219729.000000 | 95791.0 | 288988.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
24 | 32078.0 | 37753.0 | 40669.000000 | 44469.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
25 | NaN | NaN | 52668.000000 | NaN | NaN | 470665.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
26 | NaN | NaN | NaN | NaN | NaN | 170932.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
In [32]:
def drawKorea(targetData, blockedMap, cmapname): gamma = 0.75 whitelabelmin = (max(blockedMap[targetData]) - min(blockedMap[targetData]))*0.25 + \ min(blockedMap[targetData]) datalabel = targetData vmin = min(blockedMap[targetData]) vmax = max(blockedMap[targetData]) mapdata = blockedMap.pivot_table(index='y', columns='x', values=targetData) masked_mapdata = np.ma.masked_where(np.isnan(mapdata), mapdata) plt.figure(figsize=(9, 11)) plt.pcolor(masked_mapdata, vmin=vmin, vmax=vmax, cmap=cmapname, edgecolor='#AAAAAA', linewidth=0.5) # 지역 이름 표시 for idx, row in blockedMap.iterrows(): # 광역시는 구 이름이 겹치는 경우가 많아서 시단위 이름도 같이 표시한다. #(중구, 서구) if len(row['ID'].split())==2: dispname = '{}\n{}'.format(row['ID'].split()[0], row['ID'].split()[1]) elif row['ID'][:2]=='고성': dispname = '고성' else: dispname = row['ID'] # 서대문구, 서귀포시 같이 이름이 3자 이상인 경우에 작은 글자로 표시한다. if len(dispname.splitlines()[-1]) >= 3: fontsize, linespacing = 10.0, 1.1 else: fontsize, linespacing = 11, 1. annocolor = 'white' if row[targetData] > whitelabelmin else 'black' plt.annotate(dispname, (row['x']+0.5, row['y']+0.5), weight='bold', fontsize=fontsize, ha='center', va='center', color=annocolor, linespacing=linespacing) # 시도 경계 그린다. for path in BORDER_LINES: ys, xs = zip(*path) plt.plot(xs, ys, c='black', lw=2) plt.gca().invert_yaxis() plt.axis('off') cb = plt.colorbar(shrink=.1, aspect=10) cb.set_label(datalabel) plt.tight_layout() plt.show()
5-7 인구 현황 및 인구 소멸 지역 확인하기¶
- 인구 소멸 위기 지역에 대한 표현
In [33]:
drawKorea('인구수합계', pop, 'Blues')
In [34]:
pop['소멸위기지역'] = [1 if con else 0 for con in pop['소멸위기지역']] drawKorea('소멸위기지역', pop, 'Reds')
5-8 인구 현황에서¶
In [35]:
def drawKorea(targetData, blockedMap, cmapname): gamma = 0.75 whitelabelmin = 20. datalabel = targetData tmp_max = max([ np.abs(min(blockedMap[targetData])), np.abs(max(blockedMap[targetData]))]) vmin, vmax = -tmp_max, tmp_max mapdata = blockedMap.pivot_table(index='y', columns='x', values=targetData) masked_mapdata = np.ma.masked_where(np.isnan(mapdata), mapdata) plt.figure(figsize=(9, 11)) plt.pcolor(masked_mapdata, vmin=vmin, vmax=vmax, cmap=cmapname, edgecolor='#AAAAAA', linewidth=0.5) # 지역 이름 표시 for idx, row in blockedMap.iterrows(): # 광역시는 구 이름이 겹치는 경우가 많아서 시단위 이름도 같이 표시한다. #(중구, 서구) if len(row['ID'].split())==2: dispname = '{}\n{}'.format(row['ID'].split()[0], row['ID'].split()[1]) elif row['ID'][:2]=='고성': dispname = '고성' else: dispname = row['ID'] # 서대문구, 서귀포시 같이 이름이 3자 이상인 경우에 작은 글자로 표시한다. if len(dispname.splitlines()[-1]) >= 3: fontsize, linespacing = 10.0, 1.1 else: fontsize, linespacing = 11, 1. annocolor = 'white' if np.abs(row[targetData]) > whitelabelmin else 'black' plt.annotate(dispname, (row['x']+0.5, row['y']+0.5), weight='bold', fontsize=fontsize, ha='center', va='center', color=annocolor, linespacing=linespacing) # 시도 경계 그린다. for path in BORDER_LINES: ys, xs = zip(*path) plt.plot(xs, ys, c='black', lw=2) plt.gca().invert_yaxis() plt.axis('off') cb = plt.colorbar(shrink=.1, aspect=10) cb.set_label(datalabel) plt.tight_layout() plt.show()
In [36]:
pop.head()
Out[36]:
광역시도 | 시도 | 20-39세여자 | 20-39세합계 | 65세이상합계 | 인구수남자 | 인구수여자 | 인구수합계 | 소멸비율 | 소멸위기지역 | ID | y | x | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 강원도 | 강릉시 | 23098.0 | 49384.0 | 37679.0 | 106231.0 | 107615.0 | 213846.0 | 1.226041 | 0 | 강릉 | 3 | 11 |
1 | 강원도 | 고성군 | 2529.0 | 7023.0 | 7151.0 | 15899.0 | 14215.0 | 30114.0 | 0.707314 | 1 | 고성(강원) | 0 | 10 |
2 | 강원도 | 동해시 | 9753.0 | 21264.0 | 15124.0 | 47166.0 | 46131.0 | 93297.0 | 1.289738 | 0 | 동해 | 4 | 11 |
3 | 강원도 | 삼척시 | 7115.0 | 15823.0 | 14610.0 | 35253.0 | 34346.0 | 69599.0 | 0.973990 | 1 | 삼척 | 5 | 11 |
4 | 강원도 | 속초시 | 8752.0 | 18708.0 | 12752.0 | 40288.0 | 41505.0 | 81793.0 | 1.372647 | 0 | 속초 | 1 | 10 |
In [37]:
pop['여성비'] = (pop['인구수여자']/pop['인구수합계']-0.5)*100 drawKorea('여성비', pop, 'RdBu')
In [38]:
pop['2030여성비'] = (pop['20-39세여자']/pop['20-39세합계']-0.5)*100 drawKorea('2030여성비', pop, 'RdBu')
In [46]:
pop_folium = pop.set_index('ID') pop_folium
Out[46]:
광역시도 | 시도 | 20-39세여자 | 20-39세합계 | 65세이상합계 | 인구수남자 | 인구수여자 | 인구수합계 | 소멸비율 | 소멸위기지역 | y | x | 여성비 | 2030여성비 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ID | ||||||||||||||
강릉 | 강원도 | 강릉시 | 23098.0 | 49384.0 | 37679.0 | 106231.0 | 107615.0 | 213846.0 | 1.226041 | 0 | 3 | 11 | 0.323597 | -3.227766 |
고성(강원) | 강원도 | 고성군 | 2529.0 | 7023.0 | 7151.0 | 15899.0 | 14215.0 | 30114.0 | 0.707314 | 1 | 0 | 10 | -2.796042 | -13.989748 |
동해 | 강원도 | 동해시 | 9753.0 | 21264.0 | 15124.0 | 47166.0 | 46131.0 | 93297.0 | 1.289738 | 0 | 4 | 11 | -0.554680 | -4.133747 |
삼척 | 강원도 | 삼척시 | 7115.0 | 15823.0 | 14610.0 | 35253.0 | 34346.0 | 69599.0 | 0.973990 | 1 | 5 | 11 | -0.651590 | -5.033812 |
속초 | 강원도 | 속초시 | 8752.0 | 18708.0 | 12752.0 | 40288.0 | 41505.0 | 81793.0 | 1.372647 | 0 | 1 | 10 | 0.743951 | -3.217875 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
증평 | 충청북도 | 증평군 | 4554.0 | 10085.0 | 5323.0 | 19110.0 | 18198.0 | 37308.0 | 1.711065 | 0 | 13 | 6 | -1.222258 | -4.843827 |
진천 | 충청북도 | 진천군 | 7622.0 | 17013.0 | 11306.0 | 36387.0 | 33563.0 | 69950.0 | 1.348311 | 0 | 12 | 5 | -2.018585 | -5.198965 |
청주 청원 | 충청북도 | 청원구 | 27805.0 | 60021.0 | 20331.0 | 97006.0 | 93807.0 | 190813.0 | 2.735232 | 0 | 13 | 7 | -0.838255 | -3.674547 |
충주 | 충청북도 | 충주시 | 22757.0 | 49357.0 | 34790.0 | 104877.0 | 103473.0 | 208350.0 | 1.308249 | 0 | 12 | 6 | -0.336933 | -3.893065 |
청주 흥덕 | 충청북도 | 흥덕구 | 37675.0 | 78608.0 | 23459.0 | 127647.0 | 125916.0 | 253563.0 | 3.211987 | 0 | 12 | 7 | -0.341335 | -2.072308 |
252 rows × 14 columns
In [39]:
import folium import json import warnings warnings.filterwarnings(action='ignore')
In [49]:
geo_path = '../../data/05. skorea_municipalities_geo_simple.json' geo_str = json.load(open(geo_path, encoding='utf-8')) map = folium.Map(location=[36.2002, 127.054], zoom_start=7) map.choropleth(geo_data = geo_str, data=pop_folium['인구수합계'], columns=[pop_folium.index, pop_folium['인구수합계']], fill_color = 'YlGnBu', key_on='feature.id') map
Out[49]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [50]:
geo_path = '../../data/05. skorea_municipalities_geo_simple.json' geo_str = json.load(open(geo_path, encoding='utf-8')) map = folium.Map(location=[36.2002, 127.054], zoom_start=7) map.choropleth(geo_data = geo_str, data=pop_folium['소멸위기지역'], columns=[pop_folium.index, pop_folium['소멸위기지역']], fill_color = 'PuRd', key_on='feature.id') map
Out[50]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [51]:
draw_korea.to_csv("../../data/05. draw_korea.csv", encoding='utf-8', sep=',')
반응형
'데이터분석' 카테고리의 다른 글
[23.07.05] 데이터 시각화(WordCloud) - 24(1) (0) | 2023.07.05 |
---|---|
[23.07.04] 데이터 시각화(시계열 분석) - 23(1) (0) | 2023.07.04 |
[23.07.03] 데이터 시각화(기름 제일 싼 곳) - 22(1) (0) | 2023.07.03 |
[23.06.30] 데이터 시각화(따릉이) - 21(3) (0) | 2023.06.30 |
[23.06.30] 웹 크롤링(샌드위치 맛집) - 21(2) (0) | 2023.06.30 |