10. 데이터 분석하기행정구역 분석(22.07.19)
행정구역별 데이터 분석 + 블록맵]
목표:행정구역별로 공공보건의료기관 수를 파악, 인구수 대비 공공보건의료기관 비율을 비교 분석 -> 블록맵 시각화
블록맵이란?: 구역의 경계선을 단순화한 뒤 블록 형태로 그려서 지도를 나타내는 시각화 기법
1.데이터 수집
전국 공공보건의료기관 현황 데이터: 공공데이터포털 사이트에서 다운
- 공공데이터포털 -> 공공보건 의료기관 현황 검색->보건복지부 공공보건 의료기관 현황->다운로드
- 행정구역별 인구수 데이터: 이전 실습에서 사용한 행정구역시군구별__성별_인구수 파일 사용
2.데이터 준비
import pandas as pd
import numpy as np
pd.set_option('mode.chained_assignment',None)
data=pd.read_csv("data/GIS/공공보건의료기관현황.csv",index_col=0,encoding='cp949',engine='python')
data.head()
addr=pd.DataFrame(data['주소'].apply(lambda v: v.split()[:2]).tolist(),columns=('시도','군구'))
addr.head()
[01]: 데이터에서 주소값을 띄어쓰기를 기준으로 분리하여, 시군.군구에 해당하는 부분을 추출하여 addr 데이터프레임 객체를 생성
addr['시도'].unique()
[01행]: 시도 column에서 unique함수로 고윳값을 확인해보면 창원시, 경산시, 천안시가 나오는데 이 값들은 '시도'값이 아니라 '군구' 에 해당하는 값이다. 따라서 이 값들을 찾아서 바꿔줘야 한다.
addr[addr['시도']=='창원시']
addr.iloc[27]=['경상남도','창원시']
addr.iloc[31]=['경상남도','창원시']
addr[addr['시도']=='경산시']
addr.iloc[47]=['경상북도','경산시']
addr[addr['시도']=='천안시']
addr.iloc[209]=['충청남도','천안시']
addr.iloc[210]=['충청남도','천안시']
addr_aliases={'경기':'경기도','경남':'경상남도','경북':'경상북도','충북':'층청북도','서울시':'서울특별시','부산특별시':
'부산광역시','대전시':'대전광역시','충남':'충청남도','전남':'전라남도','전북':'전라북도'}
addr['시도']=addr['시도'].apply(lambda v: addr_aliases.get(v,v))
addr['시도'].unique()
[01행]: 축약된 이름과 표준이름으로 구성된 딕셔너리 생성
[02행]: '시도' column에 딕셔너리를 적용해서 컬럼값을 변경
같은방법으로 '군구' column에서도 잘못된 값을 수정한다.
addr['군구'].unique()
addr[addr['군구']=='아란13길']
addr.iloc[75]=['제주특별자치도','제주시']
addr['군구'].unique()
addr['시도군구']= addr.apply(lambda r:r['시도']+' '+r['군구'],axis=1)
addr['count']=0
addr_group=pd.DataFrame(addr.groupby(['시도','군구','시도군구'],as_index=False).count())
addr_group=addr_group.set_index('시도군구')
addr_group.head()
[01행]: '시도'와 '군구' column값을 연결하여 '시도군구' 컬럼을 추가
[02행]: count행을 추가하고 0으로 채워넣는다.
[03행]: 그룹별 원소의 개수를 구하여 count컬럼에 저장
[04행]: 데이터 병합의 기준이 되는 '시도군구' colunmn을 인덱스로 설정
다음으로 이전시간에 사용한 행정구역시군구별__성별_인구수 파일을 정리할 것이다.
population=pd.read_excel('data/GIS/행정구역_시군구_별__성별_인구수.xlsx')
population.head()
population=population.rename(columns={'행정구역(시군구)별(1)':'시도','행정구역(시군구)별(2)':'군구'})
population.head()
for element in range(len(population)):
population['군구'][element]=population['군구'][element].strip()
population['시도군구']=population.apply(lambda r:r['시도']+' '+r['군구'],axis=1)
population.head()
[01,02행]: '군구' column에서 띄어쓰기를 제거
[03행]: '시도군구' coulmn을 생성
population=population[population.군구!='소계']
population=population.set_index('시도군구')
population.head()
[01행]: '군구'의 값이 '소계'인 행은 필요없으므로 삭제
[02행]: 데이터프레임을 결합하기 위해서 동일하게 인덱스를 '시도군구'로 설정
local_population=addr_population[['시도_x','군구_x','count','총인구수 (명)']]
local_population=local_population.rename(columns={'시도_x':'시도','군구_x':'군구','총인구수 (명)':'인구수'})
mc_count=local_population['count']
local_population['Mc_ratio']=mc_count.div(local_population['인구수'],axis=0)*10000
local_population.head()
[01행]: 원하는 column만 가져온다.
[02행]: 컬럼명을 바꾼다.
[04행]: 인구수 대비 공공보건의료기관 비율울 구하여 mc_ratio 컬럼에 추가한다.
3.분석 모델 구축 및 시각화
먼저 행정구역별 공공의료기관수에 대한 차트를 그려보자.
from matplotlib import pyplot as plt
from matplotlib import rcParams, style
from matplotlib import font_manager, rc
style.use('ggplot')
font_name=font_manager.FontProperties(fname='c:/Windows/Fonts/malgun.ttf').get_name()
mc_ratio=local_population[['count']]
mc_ratio=mc_ratio.sort_values('count',ascending=False)
plt.rcParams['figure.figsize']=(25,5)
mc_ratio.plot(kind='bar',rot=90)
plt.show()
[06~10행]: 데이터프레임의 'count' column을 기준으로 오름차순 정렬을 통해 공공의료보건기관 수에 관한 차트 생성
다음으로는 행정구역별 인구수 대비 공공보건의료기관 비율에 대한 차트 생성 이다.
mc_ratio=local_population[['Mc_ratio']]
mc_ratio=mc_ratio.sort_values('Mc_ratio',ascending=False)
plt.rcParams['figure.figsize']=(25,5)
mc_ratio.plot(kind='bar',rot=90)
plt.show()
[01~05행]: 데이터프레임의 'Mc_ratio' column을 기준으로 오름차순 정렬을 통해 인구수 대비 공공의료보건기관 비율 수에 관한 차트 생성
- > 이 그래프들을 통해 공공보건의료기관수는 대전광역시 유성구와 경상남도 창원시가 가장 많고, 인구수 대비 공공보건의료기관 비율은 경상북도 울릉군이 가장 높다는 것을 시각적으로 확인할 수 있다.
마지막으로 블록맵으로 시각화를 해보자.
블록맵으로 시각화하기 위해서 구역의 경계선을 단순화해서 정리한 데이터가 필요한데 한빛출판사에서 제공되는 파일을 사용하겠다.
data_draw_korea=pd.read_csv('data/GIS/data_draw_korea.csv',index_col=0,encoding='UTF-8',engine='python')
data_draw_korea.head()
data_draw_korea['시도군구']=data_draw_korea.apply(lambda r: r['광역시도']+' '+r['행정구역'],axis=1)
data_draw_korea=data_draw_korea.set_index("시도군구")
data_draw_korea.head()
data_draw_korea_mc_population=pd.merge(data_draw_korea,local_population,how='outer',left_index=True,right_index=True)
data_draw_korea_mc_population.head()
BORDER_LINES = [
[(3, 2), (5, 2), (5, 3), (9, 3), (9, 1)],# 인천
[(2, 5), (3, 5), (3, 4), (8, 4), (8, 7), (7, 7), (7, 9), (4, 9), (4, 7), (1, 7)],# 서울
[(1, 6), (1, 9), (3, 9), (3, 10), (8, 10), (8, 9),
(9, 9), (9, 8), (10, 8), (10, 5), (9, 5), (9, 3)],# 경기도
[(9, 12), (9, 10), (8, 10)],# 강원도
[(10, 5), (11, 5), (11, 4), (12, 4), (12, 5), (13, 5),
(13, 4), (14, 4), (14, 2)],# 충청남도
[(11, 5), (12, 5), (12, 6), (15, 6), (15, 7), (13, 7),
(13, 8), (11, 8), (11, 9), (10, 9), (10, 8)],# 충청북도
[(14, 4), (15, 4), (15, 6)],# 대전시
[(14, 7), (14, 9), (13, 9), (13, 11), (13, 13)],# 경상북도
[(14, 8), (16, 8), (16, 10), (15, 10),
(15, 11), (14, 11), (14, 12), (13, 12)],# 대구시
[(15, 11), (16, 11), (16, 13)],# 울산시
[(17, 1), (17, 3), (18, 3), (18, 6), (15, 6)],# 전라북도
[(19, 2), (19, 4), (21, 4), (21, 3), (22, 3), (22, 2), (19, 2)],# 광주시
[(18, 5), (20, 5), (20, 6)],# 전라남도
[(16, 9), (18, 9), (18, 8), (19, 8), (19, 9), (20, 9), (20, 10)],# 부산시
]
def draw_blockMap(blockedMap, targetData, title, color ):
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(index='y', columns='x', values=targetData)
masked_mapdata = np.ma.masked_where(np.isnan(mapdata), mapdata)
plt.figure(figsize=(8, 13))
plt.title(title)
plt.pcolor(masked_mapdata, vmin=vmin, vmax=vmax, cmap=color, edgecolor='#aaaaaa', linewidth=0.5)
# 지역 이름 표시for idx, row in blockedMap.iterrows():
annocolor = 'white' if row[targetData] > whitelabelmin else 'black'
# 광역시는 구 이름이 겹치는 경우가 많아서 시단위 이름도 같이 표시한다. (중구, 서구)if row['광역시도'].endswith('시') and not row['광역시도'].startswith('세종'):
dispname = '{}\n{}'.format(row['광역시도'][:2], row['행정구역'][:-1])
if len(row['행정구역']) <= 2:
dispname += row['행정구역'][-1]
else:
dispname = row['행정구역'][:-1]
# 서대문구, 서귀포시 같이 이름이 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', color=annocolor,
linespacing=linespacing)
# 시도 경계 그린다.for path in BORDER_LINES:
ys, xs = zip(*path)
plt.plot(xs, ys, c='black', lw=4)
plt.gca().invert_yaxis()
#plt.gca().set_aspect(1)
plt.axis('off')
cb = plt.colorbar(shrink=.1, aspect=10)
cb.set_label(datalabel)
plt.tight_layout()
plt.savefig('data\\Gis\\+ 'blockMap_' + targetData + '.png')
plt.show()
[BORDER_LINES]: 블록맵의 행정구역 경계선을 그리기위해 행정구역의 블록위치인 X,Y데이터 정의
- >오픈소스
[def draw_blockMap ]: 블록맵의 블록에 데이터를 매핑하고 색을 표시하여 블록맵을 생성, 저장
draw_blockMap(data_draw_korea_mc_population,'count','행정구역별 공공보건의료기관 수','Blues')
draw_blockMap(data_draw_korea_mc_population,'Mc_ratio','행정구역별 인구수 대비 공공보건의료기관 비율','Reds')
위 블록맵을 통해서 바차트와 동일한 결과로 대전광역시 유성구와 경상남도 창원시가 가장 진한색의 블록으로 공공보건의료기관이 많은 것으로 나타나고, 경상북도 울릉군 그리고 전라남도 함평군이 인구수 대비 공공보건의료기관 비율이 높다는 것을 직관적으로 알 수 있다.
'데이터분석실습 > 데이터 과학 기반의 파이썬 빅데이터 분석' 카테고리의 다른 글
파이썬 빅데이터 분석 Day 12 (1) | 2023.10.26 |
---|---|
파이썬 빅데이터 분석 Day 11 (0) | 2023.10.26 |
파이썬 빅데이터 분석 Day 9 (1) | 2023.10.26 |
파이썬 빅데이터 분석 Day 8 (0) | 2023.10.26 |
파이썬 빅데이터 분석 Day 7 (1) | 2023.10.26 |