-
EDA) 인구소멸위기 지역 시각화, 카르토그램EDA 2023. 3. 10. 23:09
07. Population In [1]:import numpy as np import pandas as pd import matplotlib.pyplot as plt import set_matplotlib_hangul import warnings warnings.filterwarnings(action="ignore") %matplotlib inline
Hangul OK in your windows
fillna()¶
In [2]:datas = {"A": np.random.randint(1,45,8), "B": np.random.randint(1,45,8), "C" : np.random.randint(1,45,8)} datas
Out[2]:{'A': array([24, 20, 11, 22, 14, 21, 23, 38]), 'B': array([44, 36, 4, 31, 21, 41, 35, 24]), 'C': array([13, 38, 25, 26, 18, 5, 1, 20])}In [3]:fillna_df = pd.DataFrame(datas) fillna_df
Out[3]:A B C 0 24 44 13 1 20 36 38 2 11 4 25 3 22 31 26 4 14 21 18 5 21 41 5 6 23 35 1 7 38 24 20 In [4]:fillna_df.loc[2:4, ["A"]] = np.nan fillna_df.loc[3:5, ["B"]] = np.nan fillna_df.loc[4:7, ["C"]] = np.nan fillna_df
Out[4]:A B C 0 24.0 44.0 13.0 1 20.0 36.0 38.0 2 NaN 4.0 25.0 3 NaN NaN 26.0 4 NaN NaN NaN 5 21.0 NaN NaN 6 23.0 35.0 NaN 7 38.0 24.0 NaN In [5]:fillna_df.fillna(value=0) #nan을 0으로 채워라
Out[5]:A B C 0 24.0 44.0 13.0 1 20.0 36.0 38.0 2 0.0 4.0 25.0 3 0.0 0.0 26.0 4 0.0 0.0 0.0 5 21.0 0.0 0.0 6 23.0 35.0 0.0 7 38.0 24.0 0.0 In [6]:fillna_df.fillna(method="pad") #앞에 있는 값으로 채워줘라 # axis=1할 경우 옆에 있는 값으로 채움
Out[6]:A B C 0 24.0 44.0 13.0 1 20.0 36.0 38.0 2 20.0 4.0 25.0 3 20.0 4.0 26.0 4 20.0 4.0 26.0 5 21.0 4.0 26.0 6 23.0 35.0 26.0 7 38.0 24.0 26.0
In [7]:population = pd.read_excel("../data/07_population_raw_data.xlsx", header=1) population.fillna(method="pad", inplace=True) population
Out[7]:행정구역(동읍면)별(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 전국 소계 남자인구수 (명) 25827594.0 1877127.0 1682988.0 1806754 2045265.0 1072395.0 806680.0 600607 319391.0 113221.0 32695.0 7658 4137.0 2 전국 소계 여자인구수 (명) 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 서울특별시 소계 남자인구수 (명) 4876789.0 347534.0 372249.0 402358 410076.0 211568.0 163766.0 112076 54033.0 19595.0 6146.0 1900 1406.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 846 rows × 16 columns
In [8]:#컬럼 이름 변경 population.rename( columns = {"행정구역(동읍면)별(1)":"광역시도", "행정구역(동읍면)별(2)":"시도", "계":"인구수"}, inplace=True ) population.head()
Out[8]:광역시도 시도 항목 인구수 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 전국 소계 남자인구수 (명) 25827594.0 1877127.0 1682988.0 1806754 2045265.0 1072395.0 806680.0 600607 319391.0 113221.0 32695.0 7658 4137.0 2 전국 소계 여자인구수 (명) 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 서울특별시 소계 남자인구수 (명) 4876789.0 347534.0 372249.0 402358 410076.0 211568.0 163766.0 112076 54033.0 19595.0 6146.0 1900 1406.0 In [9]:# 소계 제거 population = population[population["시도"] !="소계"] population.head()
Out[9]:광역시도 시도 항목 인구수 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 In [10]:population.is_copy = False #카피했을 때 경고 내보내지마라 population.rename( columns = {"항목":"구분"}, inplace=True ) population.head()
Out[10]:광역시도 시도 구분 인구수 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 In [11]:# population.loc[행,열] population.loc[population["구분"] == "총인구수 (명)","구분"] = "합계" population.loc[population["구분"] == "남자인구수 (명)","구분"] = "남자" population.loc[population["구분"] == "여자인구수 (명)","구분"] = "여자" population.head()
Out[11]:광역시도 시도 구분 인구수 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 In [12]:# 소멸지역을 조사하기 위한 데이터 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["80 - 84세"] + population["85 - 89세"] + population["90 - 94세"] + population["95 - 99세"] + population["100+"])
In [13]:population.tail()
Out[13]:광역시도 시도 구분 인구수 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세이상 841 제주특별자치도 제주시 남자 235977.0 17377.0 13118.0 15084 18350.0 8474.0 6782.0 4941 2737.0 854.0 226.0 53 17.0 63929.0 26821.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 60255.0 40724.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 39298.0 34551.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 20622.0 13788.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 18676.0 20763.0 In [14]:# pivot_table pop = pd.pivot_table(data=population, index=["광역시도","시도"],columns=["구분"],values=["인구수","20-39세","65세이상"]) pop
Out[14]:20-39세 65세이상 인구수 구분 남자 여자 합계 남자 여자 합계 남자 여자 합계 광역시도 시도 강원도 강릉시 26286.0 23098.0 49384.0 17542.0 25063.0 42605.0 106231.0 107615.0 213846.0 고성군 4494.0 2529.0 7023.0 3215.0 4846.0 8061.0 15899.0 14215.0 30114.0 동해시 11511.0 9753.0 21264.0 7067.0 9988.0 17055.0 47166.0 46131.0 93297.0 삼척시 8708.0 7115.0 15823.0 6624.0 10149.0 16773.0 35253.0 34346.0 69599.0 속초시 9956.0 8752.0 18708.0 5691.0 8698.0 14389.0 40288.0 41505.0 81793.0 ... ... ... ... ... ... ... ... ... ... ... 충청북도 진천군 9391.0 7622.0 17013.0 5369.0 7816.0 13185.0 36387.0 33563.0 69950.0 청원구 32216.0 27805.0 60021.0 9386.0 13851.0 23237.0 97006.0 93807.0 190813.0 청주시 128318.0 115719.0 244037.0 42249.0 62191.0 104440.0 419323.0 415874.0 835197.0 충주시 26600.0 22757.0 49357.0 16210.0 23899.0 40109.0 104877.0 103473.0 208350.0 흥덕구 40933.0 37675.0 78608.0 10881.0 15793.0 26674.0 127647.0 125916.0 253563.0 264 rows × 9 columns
In [15]:# 소멸 비율 계산 pop["소멸비율"] = pop["20-39세", "여자"] / (pop["65세이상", "합계"] / 2)
In [16]:popOut[16]:20-39세 65세이상 인구수 소멸비율 구분 남자 여자 합계 남자 여자 합계 남자 여자 합계 광역시도 시도 강원도 강릉시 26286.0 23098.0 49384.0 17542.0 25063.0 42605.0 106231.0 107615.0 213846.0 1.084286 고성군 4494.0 2529.0 7023.0 3215.0 4846.0 8061.0 15899.0 14215.0 30114.0 0.627466 동해시 11511.0 9753.0 21264.0 7067.0 9988.0 17055.0 47166.0 46131.0 93297.0 1.143712 삼척시 8708.0 7115.0 15823.0 6624.0 10149.0 16773.0 35253.0 34346.0 69599.0 0.848387 속초시 9956.0 8752.0 18708.0 5691.0 8698.0 14389.0 40288.0 41505.0 81793.0 1.216485 ... ... ... ... ... ... ... ... ... ... ... ... 충청북도 진천군 9391.0 7622.0 17013.0 5369.0 7816.0 13185.0 36387.0 33563.0 69950.0 1.156162 청원구 32216.0 27805.0 60021.0 9386.0 13851.0 23237.0 97006.0 93807.0 190813.0 2.393166 청주시 128318.0 115719.0 244037.0 42249.0 62191.0 104440.0 419323.0 415874.0 835197.0 2.215990 충주시 26600.0 22757.0 49357.0 16210.0 23899.0 40109.0 104877.0 103473.0 208350.0 1.134758 흥덕구 40933.0 37675.0 78608.0 10881.0 15793.0 26674.0 127647.0 125916.0 253563.0 2.824848 264 rows × 10 columns
In [17]:#소멸위기지역 컬럼 생성 pop["소멸위기지역"] = pop["소멸비율"] < 1.0 pop
Out[17]:20-39세 65세이상 인구수 소멸비율 소멸위기지역 구분 남자 여자 합계 남자 여자 합계 남자 여자 합계 광역시도 시도 강원도 강릉시 26286.0 23098.0 49384.0 17542.0 25063.0 42605.0 106231.0 107615.0 213846.0 1.084286 False 고성군 4494.0 2529.0 7023.0 3215.0 4846.0 8061.0 15899.0 14215.0 30114.0 0.627466 True 동해시 11511.0 9753.0 21264.0 7067.0 9988.0 17055.0 47166.0 46131.0 93297.0 1.143712 False 삼척시 8708.0 7115.0 15823.0 6624.0 10149.0 16773.0 35253.0 34346.0 69599.0 0.848387 True 속초시 9956.0 8752.0 18708.0 5691.0 8698.0 14389.0 40288.0 41505.0 81793.0 1.216485 False ... ... ... ... ... ... ... ... ... ... ... ... ... 충청북도 진천군 9391.0 7622.0 17013.0 5369.0 7816.0 13185.0 36387.0 33563.0 69950.0 1.156162 False 청원구 32216.0 27805.0 60021.0 9386.0 13851.0 23237.0 97006.0 93807.0 190813.0 2.393166 False 청주시 128318.0 115719.0 244037.0 42249.0 62191.0 104440.0 419323.0 415874.0 835197.0 2.215990 False 충주시 26600.0 22757.0 49357.0 16210.0 23899.0 40109.0 104877.0 103473.0 208350.0 1.134758 False 흥덕구 40933.0 37675.0 78608.0 10881.0 15793.0 26674.0 127647.0 125916.0 253563.0 2.824848 False 264 rows × 11 columns
In [18]:# 소멸위기지역 조회 pop[pop["소멸위기지역"] ==True].index.get_level_values(1)
Out[18]:Index(['고성군', '삼척시', '양양군', '영월군', '정선군', '철원군', '태백시', '평창군', '홍천군', '화천군', '횡성군', '가평군', '양평군', '연천군', '거창군', '고성군', '남해군', '밀양시', '사천시', '산청군', '의령군', '창녕군', '하동군', '함안군', '함양군', '합천군', '경주시', '고령군', '군위군', '김천시', '문경시', '봉화군', '상주시', '성주군', '안동시', '영덕군', '영양군', '영주시', '영천시', '예천군', '울릉군', '울진군', '의성군', '청도군', '청송군', '동구', '서구', '영도구', '중구', '강화군', '옹진군', '강진군', '고흥군', '곡성군', '구례군', '나주시', '담양군', '무안군', '보성군', '신안군', '영광군', '영암군', '완도군', '장성군', '장흥군', '진도군', '함평군', '해남군', '화순군', '고창군', '김제시', '남원시', '무주군', '부안군', '순창군', '완주군', '임실군', '장수군', '정읍시', '진안군', '공주시', '금산군', '논산시', '보령시', '부여군', '서천군', '예산군', '청양군', '태안군', '홍성군', '괴산군', '단양군', '보은군', '영동군', '옥천군'], dtype='object', name='시도')In [19]:pop.reset_index(inplace=True) pop.head()
Out[19]:광역시도 시도 20-39세 65세이상 인구수 소멸비율 소멸위기지역 구분 남자 여자 합계 남자 여자 합계 남자 여자 합계 0 강원도 강릉시 26286.0 23098.0 49384.0 17542.0 25063.0 42605.0 106231.0 107615.0 213846.0 1.084286 False 1 강원도 고성군 4494.0 2529.0 7023.0 3215.0 4846.0 8061.0 15899.0 14215.0 30114.0 0.627466 True 2 강원도 동해시 11511.0 9753.0 21264.0 7067.0 9988.0 17055.0 47166.0 46131.0 93297.0 1.143712 False 3 강원도 삼척시 8708.0 7115.0 15823.0 6624.0 10149.0 16773.0 35253.0 34346.0 69599.0 0.848387 True 4 강원도 속초시 9956.0 8752.0 18708.0 5691.0 8698.0 14389.0 40288.0 41505.0 81793.0 1.216485 False In [20]:pop.columns.get_level_values(0)
Out[20]:Index(['광역시도', '시도', '20-39세', '20-39세', '20-39세', '65세이상', '65세이상', '65세이상', '인구수', '인구수', '인구수', '소멸비율', '소멸위기지역'], dtype='object')In [21]:tmp_columns = [ 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_columns pop.head()
Out[21]:광역시도 시도 20-39세남자 20-39세여자 20-39세합계 65세이상남자 65세이상여자 65세이상합계 인구수남자 인구수여자 인구수합계 소멸비율 소멸위기지역 0 강원도 강릉시 26286.0 23098.0 49384.0 17542.0 25063.0 42605.0 106231.0 107615.0 213846.0 1.084286 False 1 강원도 고성군 4494.0 2529.0 7023.0 3215.0 4846.0 8061.0 15899.0 14215.0 30114.0 0.627466 True 2 강원도 동해시 11511.0 9753.0 21264.0 7067.0 9988.0 17055.0 47166.0 46131.0 93297.0 1.143712 False 3 강원도 삼척시 8708.0 7115.0 15823.0 6624.0 10149.0 16773.0 35253.0 34346.0 69599.0 0.848387 True 4 강원도 속초시 9956.0 8752.0 18708.0 5691.0 8698.0 14389.0 40288.0 41505.0 81793.0 1.216485 False 3. 지도 시각화를 위한 지역별 ID 만들기¶
In [22]:pop.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 264 entries, 0 to 263 Data columns (total 13 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 광역시도 264 non-null object 1 시도 264 non-null object 2 20-39세남자 264 non-null float64 3 20-39세여자 264 non-null float64 4 20-39세합계 264 non-null float64 5 65세이상남자 264 non-null float64 6 65세이상여자 264 non-null float64 7 65세이상합계 264 non-null float64 8 인구수남자 264 non-null float64 9 인구수여자 264 non-null float64 10 인구수합계 264 non-null float64 11 소멸비율 264 non-null float64 12 소멸위기지역 264 non-null bool dtypes: bool(1), float64(10), object(2) memory usage: 25.1+ KB
In [ ]:pop["시도"].unique()
In [24]:si_name = [None] * len(pop)
In [25]:# 행정구 tmp_gu_dict = { "수원":["장안구","권선구","팔달구","영통구"], "성남":["수정구","중원구","분당구"], "안양":["만안구","동안구"], "안산":["상록구","단원구"], "고양":["덕양구","일산동구","일산서구"], "용인":["처인구","기흥구","수지구"], "청주":["상당구","서원구","흥덕구","청원구"], "천안":["동남구","서북구"], "전주":["완산구","덕진구"], "포항":["남구","북구"], "창원":["의창구","성산구","진해구","마산합포구","마산회원구"], "부천":["오정구","원미구","소사구"] }
(1) 일반 시 이름과 세종시, 광역시도 일반 구 정리¶
In [26]:pop["광역시도"]
Out[26]:0 강원도 1 강원도 2 강원도 3 강원도 4 강원도 ... 259 충청북도 260 충청북도 261 충청북도 262 충청북도 263 충청북도 Name: 광역시도, Length: 264, dtype: objectIn [27]:for idx, row in pop.iterrows(): if row["광역시도"][-3:] not in ["광역시","특별시","자치시"]: si_name[idx] = row["시도"][:-1] #마지막글자만 떼고 저장 elif row["광역시도"] == "세종특별자치시": si_name[idx] = "세종" else: if len(row["시도"]) == 2: si_name[idx] = row["광역시도"][:2] + " " +row["시도"] else: si_name[idx] = row["광역시도"][:2] + " "+row["시도"][:-1]
In [ ]:si_name(2) 행정구¶
In [29]:for idx,row in pop.iterrows(): if row["광역시도"][-3:] not in ["광역시","특별시","자치시"]: for keys, values in tmp_gu_dict.items(): if row["시도"] in values: if len(row["시도"]) == 2: si_name[idx] = keys + " " +row["시도"] elif row["시도"] in ["마산합포구","마산회원구"]: si_name[idx] = keys + " " + row["시도"][2:-1] else: si_name[idx] = keys + " " + row["시도"][:-1]
(3) 고성군¶
In [30]:for idx, row in pop.iterrows(): if row["광역시도"][-3:] not in ["광역시","특별시","자치시"]: if row["시도"][:-1] == "고성" and row["광역시도"] == "강원도": si_name[idx] = "고성(강원)" elif row["시도"][:-1] == "고성" and row["광역시도"] == "경상남도": si_name[idx] = "고성(경남)"
In [ ]:si_nameIn [32]:pop["ID"] = si_name
In [33]:popOut[33]:광역시도 시도 20-39세남자 20-39세여자 20-39세합계 65세이상남자 65세이상여자 65세이상합계 인구수남자 인구수여자 인구수합계 소멸비율 소멸위기지역 ID 0 강원도 강릉시 26286.0 23098.0 49384.0 17542.0 25063.0 42605.0 106231.0 107615.0 213846.0 1.084286 False 강릉 1 강원도 고성군 4494.0 2529.0 7023.0 3215.0 4846.0 8061.0 15899.0 14215.0 30114.0 0.627466 True 고성(강원) 2 강원도 동해시 11511.0 9753.0 21264.0 7067.0 9988.0 17055.0 47166.0 46131.0 93297.0 1.143712 False 동해 3 강원도 삼척시 8708.0 7115.0 15823.0 6624.0 10149.0 16773.0 35253.0 34346.0 69599.0 0.848387 True 삼척 4 강원도 속초시 9956.0 8752.0 18708.0 5691.0 8698.0 14389.0 40288.0 41505.0 81793.0 1.216485 False 속초 ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... 259 충청북도 진천군 9391.0 7622.0 17013.0 5369.0 7816.0 13185.0 36387.0 33563.0 69950.0 1.156162 False 진천 260 충청북도 청원구 32216.0 27805.0 60021.0 9386.0 13851.0 23237.0 97006.0 93807.0 190813.0 2.393166 False 청주 청원 261 충청북도 청주시 128318.0 115719.0 244037.0 42249.0 62191.0 104440.0 419323.0 415874.0 835197.0 2.215990 False 청주 262 충청북도 충주시 26600.0 22757.0 49357.0 16210.0 23899.0 40109.0 104877.0 103473.0 208350.0 1.134758 False 충주 263 충청북도 흥덕구 40933.0 37675.0 78608.0 10881.0 15793.0 26674.0 127647.0 125916.0 253563.0 2.824848 False 청주 흥덕 264 rows × 14 columns
In [34]:del pop["20-39세남자"] del pop["65세이상남자"] del pop["65세이상여자"]
In [35]:pop.head()
Out[35]:광역시도 시도 20-39세여자 20-39세합계 65세이상합계 인구수남자 인구수여자 인구수합계 소멸비율 소멸위기지역 ID 0 강원도 강릉시 23098.0 49384.0 42605.0 106231.0 107615.0 213846.0 1.084286 False 강릉 1 강원도 고성군 2529.0 7023.0 8061.0 15899.0 14215.0 30114.0 0.627466 True 고성(강원) 2 강원도 동해시 9753.0 21264.0 17055.0 47166.0 46131.0 93297.0 1.143712 False 동해 3 강원도 삼척시 7115.0 15823.0 16773.0 35253.0 34346.0 69599.0 0.848387 True 삼척 4 강원도 속초시 8752.0 18708.0 14389.0 40288.0 41505.0 81793.0 1.216485 False 속초 4. 지도 그리기(카르토그램)¶
In [36]:draw_korea_raw = pd.read_excel("../data/07_draw_korea_raw.xlsx") draw_korea_raw
Out[36]: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 In [37]:draw_korea_raw.stack() #몇열,몇행인지 알려줌
Out[37]:0 7 철원 8 화천 9 양구 10 고성(강원) 1 3 양주 ... 24 2 장흥 3 보성 25 2 완도 5 제주 26 5 서귀포 Length: 252, dtype: objectIn [38]:draw_korea_raw_stacked = pd.DataFrame(draw_korea_raw.stack()) draw_korea_raw_stacked
Out[38]:0 0 7 철원 8 화천 9 양구 10 고성(강원) 1 3 양주 ... ... ... 24 2 장흥 3 보성 25 2 완도 5 제주 26 5 서귀포 252 rows × 1 columns
In [39]:draw_korea_raw_stacked.reset_index(inplace=True) #인덱스가 데이터 프레임 안으로 들어오도록 draw_korea_raw_stacked
Out[39]:level_0 level_1 0 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 [40]:draw_korea_raw_stacked.rename( columns={"level_0":"y", "level_1":"x", 0:"ID"},inplace=True) draw_korea_raw_stacked
Out[40]: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 [41]:draw_korea = draw_korea_raw_stacked
In [42]: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,4),(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)], [(27,5),(27,6),(25,6)] ]
In [43]:draw_korea["ID"][33].split()
Out[43]:['서울', '서대문']
In [44]:#함수를 위한 테스트함수 def plot_text_simple(draw_korea): 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"] if len(dispname.splitlines()[-1]) >= 3: fontsize, linespacing = 9.5, 1.5 #3글자면 작게 else: fontsize, linespacing = 11, 1.5 #주석달기 plt.annotate( dispname,(row["x"] +0.5, row["y"]+0.5), # weight="bold", fontsize=fontsize, linespacing=linespacing, ha="center", #수평정렬 va="center" #수직정렬 )
In [45]:def simpleDraw(draw_korea): plt.figure(figsize=(8,11)) plot_text_simple(draw_korea) for path in BORDER_LINES: ys, xs = zip(*path) #draw_korea, border_line이 y부터 시작 plt.plot(xs, ys, c="black", lw=1.5) plt.gca().invert_yaxis() #거꾸로 plt.axis("off") plt.tight_layout() plt.show()
In [46]:simpleDraw(draw_korea)
In [47]:pop.head()
Out[47]:광역시도 시도 20-39세여자 20-39세합계 65세이상합계 인구수남자 인구수여자 인구수합계 소멸비율 소멸위기지역 ID 0 강원도 강릉시 23098.0 49384.0 42605.0 106231.0 107615.0 213846.0 1.084286 False 강릉 1 강원도 고성군 2529.0 7023.0 8061.0 15899.0 14215.0 30114.0 0.627466 True 고성(강원) 2 강원도 동해시 9753.0 21264.0 17055.0 47166.0 46131.0 93297.0 1.143712 False 동해 3 강원도 삼척시 7115.0 15823.0 16773.0 35253.0 34346.0 69599.0 0.848387 True 삼척 4 강원도 속초시 8752.0 18708.0 14389.0 40288.0 41505.0 81793.0 1.216485 False 속초 In [48]:draw_korea.head()
Out[48]:y x ID 0 0 7 철원 1 0 8 화천 2 0 9 양구 3 0 10 고성(강원) 4 1 3 양주 검증 작업¶
In [49]:#set: 정렬해서 집합으로 만들기 set(draw_korea["ID"].unique()) - set(pop["ID"].unique()) #차집합구하기(없어야 정상)
Out[49]:set()
In [50]:set(pop["ID"].unique()) - set(draw_korea["ID"].unique())
Out[50]:{'고양', '부천', '성남', '수원', '안산', '안양', '용인', '전주', '창원', '천안', '청주', '포항'}In [51]:tmp_list = list(set(pop["ID"].unique()) - set(draw_korea["ID"].unique())) for tmp in tmp_list: print(tmp) pop = pop.drop(pop[pop["ID"] == tmp].index)
창원 전주 고양 성남 부천 용인 안양 천안 안산 청주 포항 수원
In [52]:print(set(pop["ID"].unique()) - set(draw_korea["ID"].unique()))
set()
merge¶
In [53]:pop = pd.merge(pop, draw_korea, how="left", on="ID") pop.head()
Out[53]:광역시도 시도 20-39세여자 20-39세합계 65세이상합계 인구수남자 인구수여자 인구수합계 소멸비율 소멸위기지역 ID y x 0 강원도 강릉시 23098.0 49384.0 42605.0 106231.0 107615.0 213846.0 1.084286 False 강릉 3 11 1 강원도 고성군 2529.0 7023.0 8061.0 15899.0 14215.0 30114.0 0.627466 True 고성(강원) 0 10 2 강원도 동해시 9753.0 21264.0 17055.0 47166.0 46131.0 93297.0 1.143712 False 동해 4 11 3 강원도 삼척시 7115.0 15823.0 16773.0 35253.0 34346.0 69599.0 0.848387 True 삼척 5 11 4 강원도 속초시 8752.0 18708.0 14389.0 40288.0 41505.0 81793.0 1.216485 False 속초 1 10 그림을 그리기 위한 데이터 계산하는 함수¶
- 색상을 만들 때 최소값을 흰색
- blockedMap: 인구현황 (pop) =데이터프레임
- targetData: 그리고 싶은 컬럼
In [54]:def get_data_info(targetData, blockedMap): whitelabelmin = ( max(blockedMap[targetData] - min(blockedMap[targetData]) ) * 0.25 + min(blockedMap[targetData])) vmin = min(blockedMap[targetData]) vmax = max(blockedMap[targetData]) mapdata = blockedMap.pivot_table(index="y", columns = "x", values=targetData) #targetData의 숫자가 들어감 return mapdata, vmax, vmin, whitelabelmin
In [55]:#색상 만들 때 중간값을 흰색으로 def get_data_info_for_zero_center(targetData, blockedMap): whitelabelmin = 5 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) return mapdata, vmax, vmin, whitelabelmin
In [56]:def plot_text(targetData,blockedMap, whitelabelmin): 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"] if len(dispname.splitlines()[-1]) >= 3: fontsize, linespacing = 9.5, 1.5 #3글자면 작게 else: fontsize, linespacing = 11, 1.5 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, color = annocolor, linespacing=linespacing, ha="center", #수평정렬 va="center" #수직정렬 )
In [57]:def draw_korea(targetData, blockedMap, cmapname, zeroCenter = False): if zeroCenter: masked_mapdata, vmax, vmin, whitelabelmin = get_data_info_for_zero_center(targetData, blockedMap) if not zeroCenter: masked_mapdata, vmax, vmin, whitelabelmin = get_data_info(targetData, blockedMap) plt.figure(figsize=(8,11)) plt.pcolor(masked_mapdata, vmin=vmin, vmax=vmax, cmap=cmapname, edgecolor="#aaaaaa", linewidth=0.5) plot_text(targetData, blockedMap, whitelabelmin) for path in BORDER_LINES: ys, xs = zip(*path) plt.plot(xs, ys, c="black", lw=1.5) plt.gca().invert_yaxis() #거꾸로 plt.axis("off") plt.tight_layout() cb = plt.colorbar(shrink=0.1, aspect=10) #컬러바 길이 지정 cb.set_label(targetData) plt.show()
In [58]:draw_korea("인구수합계", pop, "Blues" )
In [59]:pop["소멸위기지역"] = [1 if con else 0 for con in pop["소멸위기지역"]] #con=True면 1, False면 0 draw_korea("소멸위기지역", pop, "Reds")
In [60]:pop["여성비"] = (pop["인구수여자"] / pop["인구수합계"] - 0.5) * 100 draw_korea("여성비", pop, "RdBu", zeroCenter=True)
In [61]:pop["2030여성비"] = (pop["20-39세여자"] / pop["20-39세합계"] - 0.5) * 100 draw_korea("2030여성비", pop, "RdBu", zeroCenter=True)
In [62]:import folium import json pop_folium = pop.set_index("ID") pop_folium.head()
Out[62]:광역시도 시도 20-39세여자 20-39세합계 65세이상합계 인구수남자 인구수여자 인구수합계 소멸비율 소멸위기지역 y x 여성비 2030여성비 ID 강릉 강원도 강릉시 23098.0 49384.0 42605.0 106231.0 107615.0 213846.0 1.084286 0 3 11 0.323597 -3.227766 고성(강원) 강원도 고성군 2529.0 7023.0 8061.0 15899.0 14215.0 30114.0 0.627466 1 0 10 -2.796042 -13.989748 동해 강원도 동해시 9753.0 21264.0 17055.0 47166.0 46131.0 93297.0 1.143712 0 4 11 -0.554680 -4.133747 삼척 강원도 삼척시 7115.0 15823.0 16773.0 35253.0 34346.0 69599.0 0.848387 1 5 11 -0.651590 -5.033812 속초 강원도 속초시 8752.0 18708.0 14389.0 40288.0 41505.0 81793.0 1.216485 0 1 10 0.743951 -3.217875 In [63]:geo_path = "../data/07_skorea_municipalities_geo_simple.json" geo_str = json.load(open(geo_path, encoding = "utf-8")) mymap = folium.Map(location=[36.2002, 127.054],zoom_start = 7) #인구수합계 시각화 mymap.choropleth( geo_data=geo_str, data=pop_folium["인구수합계"], key_on="feature.id", columns=[pop_folium.index, pop_folium["인구수합계"]], fill_color="YlGnBu") mymap
Out[63]:Make this Notebook Trusted to load map: File -> Trust NotebookIn [64]:#소멸위기지역 시각화 mymap.choropleth( geo_data=geo_str, data=pop_folium["소멸위기지역"], key_on="feature.id", columns=[pop_folium.index, pop_folium["소멸위기지역"]], fill_color="PuRd") mymap
Out[64]:Make this Notebook Trusted to load map: File -> Trust Notebook'EDA' 카테고리의 다른 글
EDA) 네이버 API 활용 (0) 2023.03.10 EDA) 셀프 주유소 가격 분석 (0) 2023.03.10 EDA) Selenium 기초 (0) 2023.03.10 EDA) 네이버 영화순위 시각화 (0) 2023.03.10 EDA) 웹크롤링 기초 예제 - 시카고 샌드위치 (0) 2023.03.10