🖥️ IT, 컴퓨터/🐍 Python
[Python] 생활인구 데이터 파이썬 코드 템플릿
김 홍시
2025. 3. 9. 16:28
반응형
1. 기본 전처리
#0.1. 파일 업로드
import pandas as pd
df = pd.read_csv("당신의경로/LOCAL_PEOPLE_20240406.csv", encoding="euc-kr")
df = df.rename(columns={'?"기준일ID"': "date", '시간대구분':'time', '행정동코드':'통계청dong_cd',"집계구코드":'jgg_cd',
"남자0세부터9세생활인구수":'man00-09', "남자10세부터14세생활인구수":'man10-14', "남자15세부터19세생활인구수": "man15-19", "남자20세부터24세생활인구수": "man20-24",
"남자25세부터29세생활인구수": "man25-29", "남자30세부터34세생활인구수": "man30-34",
"남자35세부터39세생활인구수": "man35-39", "남자40세부터44세생활인구수": "man40-44",
"남자45세부터49세생활인구수": "man45-49", "남자50세부터54세생활인구수": "man50-54",
"남자55세부터59세생활인구수": "man55-59", "남자60세부터64세생활인구수": "man60-64",
"남자65세부터69세생활인구수": "man65-69", "남자70세이상생활인구수": "man70+",
"여자0세부터9세생활인구수": "woman00-09", "여자10세부터14세생활인구수": "woman10-14",
"여자15세부터19세생활인구수": "woman15-19", "여자20세부터24세생활인구수": "woman20-24",
"여자25세부터29세생활인구수": "woman25-29", "여자30세부터34세생활인구수": "woman30-34",
"여자35세부터39세생활인구수": "woman35-39", "여자40세부터44세생활인구수": "woman40-44",
"여자45세부터49세생활인구수": "woman45-49", "여자50세부터54세생활인구수": "woman50-54",
"여자55세부터59세생활인구수": "woman55-59", "여자60세부터64세생활인구수": "woman60-64",
"여자65세부터69세생활인구수": "woman65-69", "여자70세이상생활인구수": "woman70+"})
df = df.replace('*', 0)
df.head(10)
길이가 긴 열 이름을 변경하고,
*으로 나오는 값을 0으로 변경한 결과
# 0.2. 집계구코드_동정보 join
df_kt = pd.read_csv(r"당신의경로/KT생활인구집계구.csv")
# jgg_cd를 기준으로 df에 df_kt를 왼쪽 조인 (df 기준)
df_merged = df.merge(df_kt, on='jgg_cd', how='left')
df_merged = df_merged.rename(columns={"emd_cd": "행안부emd_cd",})
column_order = ['date', 'time', '통계청dong_cd', 'emd_nm', '행안부emd_cd', 'jgg_cd', '총생활인구수', 'man00-09', 'man10-14',
'man15-19', 'man20-24', 'man25-29', 'man30-34', 'man35-39', 'man40-44',
'man45-49', 'man50-54', 'man55-59', 'man60-64', 'man65-69', 'man70+',
'woman00-09', 'woman10-14', 'woman15-19', 'woman20-24', 'woman25-29',
'woman30-34', 'woman35-39', 'woman40-44', 'woman45-49', 'woman50-54',
'woman55-59', 'woman60-64', 'woman65-69', 'woman70+' ]
# df_merged의 열 순서 변경
df_merged = df_merged[column_order]
df_merged.head(10)
집계구 파일 다운 받아 위와 같이 코드 입력하면
해당 집계구가 무슨 동에 해당하는지 알 수 있음
#0.3 folium 지도 세팅
import folium
import geopandas as gpd
from IPython.core.display import HTML
# 📌 Shapefile 로드
shapefile1_path = "당신의경로/행정구역.shp"
shapefile2_path = "당신의경로/집계구.shp"
gdf1 = gpd.read_file(shapefile1_path) # 행정구역
gdf2 = gpd.read_file(shapefile2_path) # 집계구
# 📌 좌표계 확인 및 변환 (EPSG:4326)
if gdf1.crs != "EPSG:4326":
gdf1 = gdf1.to_crs(epsg=4326)
if gdf2.crs != "EPSG:4326":
gdf2 = gdf2.to_crs(epsg=4326)
# 📌 투영 좌표계 변환 후 중심 좌표 계산
gdf_proj = gdf1.to_crs(epsg=3857) # EPSG:3857로 변환
centroid = gdf_proj.geometry.centroid.to_crs(epsg=4326) # 다시 EPSG:4326으로 변환
# 📌 folium 지도 생성 (중심 좌표 설정)
m = folium.Map(
location=[centroid.y.mean(), centroid.x.mean()],
zoom_start=12
)
# 📌 GeoJson 변환 및 스타일 적용 (첫 번째 레이어: 행정구역)
folium.GeoJson(
gdf1,
name="행정구역",
style_function=lambda x: {
"fillColor": "grey",
"color": "black",
"weight": 1,
"fillOpacity": 0.0
}
).add_to(m)
# 📌 GeoJson 변환 및 스타일 적용 (두 번째 레이어: 집계구, 툴팁 추가)
folium.GeoJson(
gdf2,
name="집계구",
style_function=lambda x: {
"fillColor": "blue",
"color": "darkblue",
"weight": 0.5,
"fillOpacity": 0.2
},
tooltip=folium.GeoJsonTooltip(
fields=["TOT_REG_CD", "ADM_NM"], # 툴팁에 표시할 필드
aliases=["집계구코드:", "행정동:"], # 툴팁에서 보일 레이블
localize=True
)
).add_to(m)
# 📌 지도에 레이어 컨트롤 추가 (켜고 끌 수 있음)
folium.LayerControl().add_to(m)
# 📌 HTML 스타일을 이용한 지도 높이 조절
map_height = 600 # 원하는 지도 높이 설정
HTML(f'<div style="width: 100%; height: {map_height}px;">{m._repr_html_()}</div>')
집계구 / 읍면동 함께 보이는 지도 세팅하는 코드
위 코드 실행 전에 아래 파일 받아서 압축 풀어둘 것(행정구역, 집계구 shp)
이렇게 마우스 오버 시, 해당 집계구가 어떤 행정동에 해당하는지 보임.
이제 기본 세팅은 끝
2. 총생활인구 수 기준으로 정렬하기
# 1. 총생활인구수 랭킹
df_총인구수 = df_merged[['date', 'time', '통계청dong_cd', 'emd_nm', '행안부emd_cd', 'jgg_cd', '총생활인구수']]
df_총인구수 = df_총인구수[df_총인구수['time'] == 15] # time이 15인 데이터만 필터링
df_총인구수 = df_총인구수.sort_values(by='총생활인구수', ascending=False)
df_총인구수.head(20)
import folium
import geopandas as gpd
import pandas as pd
import random
from IPython.display import display, HTML
# 파일 로드 및 EPSG 변환 함수 정의
def load_and_transform_shapefile(path, target_crs="EPSG:4326"):
gdf = gpd.read_file(path)
if gdf.crs != target_crs:
gdf = gdf.to_crs(epsg=int(target_crs.split(":")[1]))
return gdf
# 경로 설정
shapefile1_path = "당신의경로/행정구역.shp"
shapefile2_path = "당신의경로/집계구.shp"
gdf1 = load_and_transform_shapefile(shapefile1_path) # 행정구역
gdf2 = load_and_transform_shapefile(shapefile2_path) # 집계구
# 총생활인구수 데이터 로드 (df_총인구수가 주어진다고 가정)
df_총인구수 = df_총인구수[df_총인구수['time'] == 15] # 특정 시간대(15시) 필터링
# 상위 20개 집계구 코드 추출 (1~10위, 11~20위 분리)
top_10_jgg_cd = set(df_총인구수["jgg_cd"].head(10)) # 1~10위
top_11_20_jgg_cd = set(df_총인구수["jgg_cd"].iloc[10:20]) # 11~20위
# gdf2에 총생활인구수 데이터 병합
gdf2 = gdf2.merge(df_총인구수[['jgg_cd', '총생활인구수']], on='jgg_cd', how='left')
# 지도 중심 계산
gdf_proj = gdf1.to_crs(epsg=3857)
centroids = gdf_proj.geometry.centroid.to_crs(epsg=4326)
centroid_y, centroid_x = centroids.y.mean(), centroids.x.mean()
# Folium 지도 생성
m = folium.Map(location=[centroid_y, centroid_x], zoom_start=12)
# 행정구역 GeoJson 추가
folium.GeoJson(
gdf1,
name="행정구역",
style_function=lambda _: {"fillColor": "grey", "color": "black", "weight": 1, "fillOpacity": 0.0},
).add_to(m)
# 집계구 스타일 함수 (순위별 색상 적용)
def get_top_20_style(feature):
jgg_cd = feature["properties"].get("jgg_cd")
if jgg_cd in top_10_jgg_cd:
color = "red" # 1~10위: 빨간색
elif jgg_cd in top_11_20_jgg_cd:
color = "pink" # 11~20위: 분홍색
else:
color = "blue" # 나머지: 파란색
return {
"fillColor": color,
"color": "black",
"weight": 0.5,
"fillOpacity": 0.7 if jgg_cd in top_10_jgg_cd or jgg_cd in top_11_20_jgg_cd else 0.1,
}
# 집계구 GeoJson 추가 (툴팁에 '총생활인구수' 추가)
folium.GeoJson(
gdf2,
name="집계구",
style_function=get_top_20_style,
tooltip=folium.GeoJsonTooltip(
fields=["TOT_REG_CD", "ADM_NM", "총생활인구수"], # 총 3개 필드 포함
aliases=["집계구코드:", "행정동:", "총생활인구수:"],
localize=True
),
).add_to(m)
# 상위 20개 집계구 마커 추가
for _, row in gdf2[gdf2["jgg_cd"].isin(top_10_jgg_cd | top_11_20_jgg_cd)].iterrows():
centroid = row.geometry.centroid
folium.Marker(
location=[centroid.y + random.uniform(-0.001, 0.001), centroid.x + random.uniform(-0.001, 0.001)],
icon=folium.DivIcon(
html=f'<div style="font-size:10px; color:black; font-weight:bold; background-color:white; padding:2px; border-radius:3px;">{row["ADM_NM"]}</div>'
),
).add_to(m)
# 레이어 컨트롤 추가
folium.LayerControl().add_to(m)
# 지도 출력
display(HTML(f'<div style="width: 100%; height: 600px;">{m._repr_html_()}</div>'))
# 지도 저장
m.save("C:/Users/jiyun/OneDrive/바탕 화면/map.html")
마우스 스크롤 확대/축소 감도 조절
상위 1위-10위 - 빨간색,
상위 11위-20위 - 분홍색 설정되도록 조절
추가로 해결해야 할 과제
집계구는 울퉁불퉁하다는 문제가 있음.
어떻게 100m by 100m으로 맵핑시킬지
반응형