데이터 분석(Data Analysis)/쉽게 배우는 파이썬 데이터 분석

[넷째마당_다양한 데이터 분석의 세계] 11 지도 시각화

Kim MyeongOk 2023. 12. 31. 09:13

넷째마당_11_지도시각화__쉽게배우는파이썬데이터분석.hwp
1.98MB

지역별 특징을 지도에 색깔로 표현한 단계 구분도를 만드는 방법을 알아봄.


11-1 시군구별 인구 단계 구분도 만들기

지역별 통계치를 색깔 차이로 표현한 지도를 단계 구분도(choropleth map)라고 함. 단계 구분도를 만들면 인구나 소득 같은 통계치가 지역별로 어떻게 다른지 쉽게 이해할 수 있음. 시군구별 인구 데이터를 이용해 단계 구분도를 만들어 보겠음.

import json
geo = json.load(open('SIG.geojson', encoding = 'UTF-8'))

tip) json.load()GeoJSON 파일을 불러오려면 open()을 이용해 파일을 열어야 함.

tip) GeoJSON은 위치 정보를 JSON 포맷으로 저장한 표준 지리 정보 데이터 포맷임. 지리 정보 데이터를 다루는 대부분의 소프트웨어에서 GeoJSON 파일을 활용할 수 있음. 이 책에서 사용하는 GeoJSON 파일은 '()지오서비스'에서 공개한 SHP 파일을 오픈 소스 지리 정보 시스템 QGIS로 변환해 만들었음.

- 데이터 출처: bit.ly/easypy_111

 

geo는 딕셔너리 자료 구조로 되어 있음. geoproperties에 들어 있는 SIG_CD에 지역을 나타내는 행정 구역 코드가 담겨 있고, geometry에 시군구의 경계를 나타낸 위도, 경도 좌표가 담겨 있음.

# 행정 구역 코드 출력
geo['features'][0]['properties']

# output: {'SIG_CD': '42110', 'SIG_ENG_NM': 'Chuncheon-si', 'SIG_KOR_NM': '춘천시'}
# 위도, 경도 좌표 출력
geo['features'][0]['geometry']

(...생략...)

 

2. 시군구별 인구 데이터 준비하기

지도에 표현할 시군구별 인구 통계 데이터가 담겨 있는 Population_SIG.csv 파일을 불러오겠음. Population_SIG.csv 파일은 2021년의 시군구별 행정 구역 코드, 지역 이름, 인구를 담고 있음.

tip) Population_SIG.csv는 국가통계포털 KOSIS'주민등록인구현황' 데이터를 가공해 만들었음.

- 데이터 출처: bit.ly/easypy_112

tip) 통계 데이터에 행정 구역 코드가 들어 있어야 지도를 만드는 데 활용할 수 있음. KOSIS의 다운로드 화면에서 '파일 형태''코드포함'을 체크하면 행정 구역 코드를 함께 다운로드함.

 

import pandas as pd
df_pop = pd.read_csv('Population_SIG.csv')
df_pop.head()

df_pop.info()

 

 

행정 구역 코드를 나타낸 df_pop code int64 타입으로 되어있음. 행정 구역 코드가 문자 타입으로 되어 있어야 지도를 만드는데 활용할 수 있음. df.astype()을 이용해 code를 문자 타입으로 바꾸겠음.

df_pop['code'] = df_pop['code'].astype(str)

 

3. 단계 구분도 만들기

folium 패키지를 이용하면 단계 구분도를 만들 수 있음. 아나콘다 프롬프트에서 folium 패키지를 설치하겠음.

pip install folium

 

(1) 배경 지도 만들기

folium.Map()을 이용해 배경 지도를 만들어 보겠음. location에는 지도의 중심 위도, 경도 좌표를 입력하고, zoom_start에는 지도를 확대할 정도로 입력함. folium으로 만든 지도는 마우스를 이용해 위치를 옮길 수 있고, 휠을 이용해 확대하거나 축소할 수 있음.

folium.Map()에서 Map() M은 대문자이니 주의하기 바람.

import folium
folium.Map(location = [35.95, 127.7], # 지도 중심 좌표
           zoom_start = 8)            # 확대 단계

tip) 지도 크기는 모니터 크기와 해상도에 따라 달라짐. 다음과 같이 folium.Map(location = [35.95, 127.7], zoom_start = 8, width = '80%', height = '80%')

 

단계 구분도를 만드는 데 사용할 대병 지도를 만들어 저장하겠음. 지도 종류는 단계 구분도가 잘 표현되도록 밝은색으로 바꾸겠음. tiles'cartodbpositron'를 입력하면 됨.

map_sig = folium.Map(location = [35.95, 127.7], # 지도 중심 좌표
                     zoom_start = 8,            # 확대 단계
                     tiles = 'cartodbpositron') # 지도 종류
map_sig

 

(2) 단계 구분도 만들기

folium.Choropleth()를 이용해 시군구별 인구를 나타낸 단계 구분도를 만들겠음. folium.Choropleth()에는 다음과 같은 파라미터를 입력함.

geo_data: 지도 데이터

- data: 색깔로 표현할 통계 데이터

- columns: 통계 데이터의 행정 구역 코드 변수, 색깔로 표현할 변수

- key_on: 지도 데이터의 행정 구역 코드

 

folium.Choropleth().add_to(map_sig)를 추가하면 앞에서 만든 배경 지도 map_sig에 단계 구분도를 덧씌움. map_sig를 실행하면 시군구 경계가 표시된 지도가 출력됨.

folium.Choropleth(
    geo_data = geo,
    data = df_pop,
    columns = ('code', 'pop'),
    key_on = 'feature.properties.SIG_CD') \
      .add_to(map_sig)

map_sig

tip) folium.Choropleth()를 실행하면 PC 환경에 따라 시간이 오래 걸릴 수 있음. 코드를 실행 중일 때는 셀 왼쪽에 [*]가 표시됨. 실행하면 [ ]에 셀 실행 순서를 나타낸 번호가 표시됨.

 

 

(3) 계급 구간 정하기

앞에서 출력한 지도는 지역이 색깔별로 표현되어 있지 않음. 지역을 단계별로 나눌 때 기준으로 삼은 '계급 구간'이 적단하지 않기 때문임.

분위수를 이용해 지역을 적당히 나누는 계급 구간을 정하겠음. quantile()을 이용해 5가지 계급 구간의 하한값, 상한값을 담은 bins를 만듦. 이렇게 구한 값을 folium.Choropleth()bins에 입력하면 지역을 인구에 따라 다섯 단계의 색깔로 표현함.

tip) quantile()은 값을 크기순으로 나열한 다음 입력한 비율에 해당하는 값인 '분위수'를 구하는 함수임.

bins = list(df_pop['pop'].quantile([0, 0.2, 0.4, 0.6, 0.8, 1]))
bins

# output: [8867.0, 50539.6, 142382.20000000004, 266978.6, 423107.20000000024, 13565450.0]

tip) list()라는 자료 구조는 리스트를 변환하는 함수임. 계급 구간을 folium.Choropleth()에 활용하려면 리스트로 되어 있어야 함. 리스트는 17-3절에서 자세히 다룸.

tip) folium.Choropleth()는 통계치가 가장 작은 값부터 큰 값까지 6개의 일정한 간격으로 계급 구간을 만들어 지역의 색깔을 정함. 그런데 통계치가 극단적으로 큰 지역이 있으면 6개의 계급 구간으로 지역을 적절하게 구분하지 못하므로 모든 지역이 같은 색으로 표현됨. 앞에서 만든 지도는 '경기도''서울 특별시'의 인구가 다른 지역에 비해 극단적으로 크기 때문에 다른 지역이 같은 색으로 표현된 것임.

 

(4) 디자인 수정하기

파라미터를 몇 가지 추가해 단계 구분도의 디자인을 보기 좋게 수정하겠음. 출력한 단계 구분도를 보면 인구가 많을수록 파란색, 적을수록 노란색에 가깝게 표현되어 시군구별 인구 차이를 한눈에 알 수 있음.

map_sig = folium.Map(location = [35.95, 127.7], # 지도 중심 좌표
                     zoom_start = 8,            # 확대 단계
                     tiles = 'cartodbpositron') # 지도 종류
# 단계구분도 만들기
folium.Choropleth(
    geo_data = geo,
    data = df_pop,
    columns = ('code', 'pop'),
    key_on = 'feature.properties.SIG_CD',
    fill_color = 'YlGnBu',
    fill_opacity = 1,
    line_opadity = 0.5,
    bins = bins) \
      .add_to(map_sig)

map_sig


11-2 서울시 동별 외국인 인구 단계 구분도 만들기

단계 구분도는 최적의 장소를 정하는 데 유용하게 활용할 수 있음. 만약 지자체가 외국인의 생활을 돕는 시설을 지을 장소를 정한다면, 지역별 외국인 인구를 나타낸 단계 구분도를 만들면 도움이 될 것임. 이번에는 서울시의 동별 외국인 인구 데이터를 이용해 단계 구분도를 만들어 보겠음.

 

[Do it! 실습] 서울시 동별 외국인 인구 단계 구분도 만들기

1. 서울시 동 경계 지도 데이터 준비하기

서울시의 동 경계 좌표가 들어 있는 EMD_Seoul.geojson 파일을 불러오겠음. EMD_Seoul.geojson 파일은 서울시의 동별 행정 구역 코드, 동 이름, 동 경계 위도, 경도 좌표를 담고 있음.

import json
geo_seoul = json.load(open('EMD_Seoul.geojson', encoding = 'UTF-8'))

 

geo_seoulproperties에 들어 있는 ADM_DR_CD에 동을 나타내는 행정 구역 코드가 담겨 있고, geometry에 동별 경계를 나타낸 위도와 경도 좌표가 담겨 있음.

# 행정 구역 코드 출력
geo_seoul['features'][0]['properties']

# 위도, 경도 좌표 출력
geo_seoul['features'][0]['geometry']

(...생략...)

 

2. 서울시 동별 외국인 인구 데이터 준비하기

서울시 동별 외국인 인구 통계가 들어있는 Foreigner_EMD_Seoul.csv 파일을 불러오겠음. Foreigner_EMD_Seoul.csv 파일은 2021년 서울의 동별 행정 구역 코드, 동 이름, 외국인 인구를 담고 있음.

tip) Foreigner_EMD_Seoul.csv 파일은 국가통계포털 KOSIS'지방자치단체외국인주민현황' 데이터를 가공해 만들었음.

- 데이터 출처: bit.ly/easypy_113

foreigner = pd.read_csv('Foreigner_EMD_Seoul.csv')
foreigner.head()

foreigner.info()

 

행정 구역 코드를 나타낸 foreignercodeint64 타입으로 되어 있음. 지도를 만드는 데 활용할 수 있도록 문자 타입으로 바꾸겠음.

foreigner['code'] = foreigner['code'].astype(str)

 

3. 단계 구분도 만들기

단계 구분도를 만들겠음. 우선 지역을 8단계로 나누도록 8개 계급 구간의 하한값, 상한값을 만들겠음.

bins = list(foreigner['pop'].quantile([0, 0.2, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]))
bins

# output: [7.0, 98.0, 200.0, 280.0, 386.0, 529.5, 766.0, 1355.5, 26896.0]

 

서울이 가운데 오도록 배경 지도를 만든 다음 단계 구분도를 추가하겠음. 인구가 많을수록 진한 파란색으로 표현하도록 fill_color = 'Blues'를 입력하고 , 외국인 인구가 결측치인 지역은 흰색으로 표현하도록 nan_fill_color = 'white'를 입력하겠음.

# 배경 지도 만들기
map_seoul = folium.Map(location = [37.56, 127],
                   zoom_start = 12,
                   tiles = 'cartodbpositron')

# 단계 구분도 만들기
folium.Choropleth(
    geo_data = geo_seoul,
    data = foreigner,
    columns = ('code', 'pop'),
    key_on = 'feature.properties.ADM_DR_CD',
    fill_color = 'Blues',
    nan_fill_color = 'white',
    fill_opacity = 1,
    line_opadity = 0.5,
    bins = bins) \
      .add_to(map_seoul)
map_seoul

 

4. 구 경계선 추가하기

앞에서 만든 지도에 구 경계선을 추가하겠음. 먼저 서울시의 구 경계 좌표를 담은 SIG_Seoul.geojson 파일을 불러오겠음.

geo_seoul_sig = json.load(open('SIG_Seoul.geojson', encoding = 'UTF-8'))

서울시 구 경계선을 이용해 단계 구분도를 만든 다음 .add_to(map_seoul_gu) 이용해 앞에서 만든 지도에 추가하겠음. 색깔은 칠하지 않도록 fill_opacity = 0을 입력하고, 구 경계선을 두껍게 나타내도록 line_weight = 4를 입력하겠음. 출력한 지도를 보면 외국인 인구가 많은 지역과 적은 지역을 쉽게 알아볼 수 있음.

# 서울 구 라인 추가
folium.Choropleth(geo_data = geo_seoul_sig,
                  fill_opacity = 0,
                  line_weight = 4) \
      .add_to(map_seoul)
map_seoul

 

{알아 두면 좋아요} folium 활용하기

HTML 파일로 저장하기

save() 메서드를 이용하면 지도를 HTML 파일로 저장할 수 있음. HTML 파일은 파이썬과 JupyterLab이 설치되지 않은 곳에서도 웹 브라우저만 있으면 열어볼 수 있음.

map_seoul.save('map_seoul.html')

 

웹 브라우저에서 html 파일 열기

webbrowser 패키지의 open_new()를 이용하면 웹 브라우저에서 HTML 파일을 열 수 있음. 지도가 너무 커서 노트북에서 보기 어려울 때 HTML 파일로 저장한 다음 웹 브라우저에서 열면 편리함.

import webbrowser
webbrowser.open_new('map_seoul.html')

 

 

다른 지도 만들기

folium 패키지를 이용하면 단계 구분도 외에 다른 종류의 지도를 만들 수 있고 디자인도 다양하게 수정할 수 있음. folium 공식 문서를 참고하기 바람.

- folium 공식 문서: python-visualization.github.io/folium

 

 

 

 

- 11장 END -