1. 기술개요
QGIS를 이용해 공간 데이터를 다루면 시각적으로 편리하지만, 데이터가 크거나 월별·지역별 반복 작업이 많을 경우 처리 속도가 느리고 수동 작업이 늘어납니다
이를 해결하기 위해 Python과 GeoPandas를 활용하면, QGIS 없이도 좌표 변환, 공간 필터링, 격자화 등 전처리를 자동화할 수 있습니다.
Python을 활용해 대용량 유동인구 데이터를 효율적으로 전처리하고, 특정 지역 내 인구 데이터를 필터링하여 격자 형태의 공간 데이터를 자동으로 생성하는 방법을 단계별로 소개하겠습니다.
가. 공간 연산
– 지리적 객체(점, 선, 면 등)의 위치 관계를 계산하거나 비교하는 과정을 말합니다.
– GeoPandas에서는 sjoin() 함수를 통해 이러한 공간 연산을 코드 한 줄로 수행할 수 있습니다.
| predicate | 설명 |
| within | 포인트가 폴리곤 내부에 포함된 경우 |
| contains | 폴리곤이 포인트를 포함하는 경우 |
| intersects | 두 객체가 경계나 내부에서 서로 닿는 경우 |
| touches | 두 객체가 경계에서만 맞닿는 경우 |
| overlaps | 두 객체가 일부 겹치는 경우 |
<sjoin()함수 매개변수 설명>
나. 격자 데이터
– 일정한 가격의 셀(정사각형 단위)로 공간을 나누어 각 셀마다 특정 값을 부여한 공간 데이터를 의미합니다.
– 행정구역 단위보다 세밀하게 공간적 분포를 표현할 수 있어, 인구 · 매출 · 교통량 등 다양한 지표를 균일한 단위로 비교 및 분석할 때 활용합니다.
– 아래 예시와 같이 격자는 분석 목적과 데이터 종류에 따라 크기가 달라집니다.

<(좌)격자 50×50, (우)격자 100×100>
다. 통신 데이터
– 이동통신 기지국에 접속한 단말기의 위치 정보를 기반으로, 특정 시·공간 내 인구의 분포와 이동 흐름을 파악할 수 있는 데이터입니다.
– 시간대별·요일별·성별·연령대별로 인구 특성을 세분화할 수 있어, 상권 분석, 관광 트렌드 진단, 도시 생활패턴 분석 등 다양한 분야에서 활용되고 있습니다.
– 예를 들어, SKT 유동인구 데이터는 행정동 또는 50×50격자 단위로 시간별(예: 1시간 단위) 인구수를 제공합니다
| 컬럼명 | 설명 |
| etl_ymd | 수집 일자 (예: 20250101) |
| admi_cd | 행정구역 코드 |
| cty_nm | 시도명 |
| admi_nm | 시군구명 |
| cell_id | 격자 ID |
| utmk_x / utmk_y | 격자 중심좌표 (UTMK 기준) |
| time_cd | 시간대 코드 |
| pop | 해당 격자 내 유동인구 수 |
<skt 유동인구 데이터>
– 또한, SKT 유동인구 데이터의 좌표계는 UTM-K(EPSG:5179)로, GRS80 타원체를 기준으로 한 한국형 UTM(UTM Zone 52N 변형) 좌표체계를 사용합니다.
– 이 좌표계는 미터 단위의 평면좌표를 사용하기 때문에, QGIS 등 공간분석 도구에서 격자 생성이나 면적 계산 시 위치 왜곡 없이 정확한 공간 분석이 가능합니다.
2. 기술 사용 상세
가. 사용 라이브러리 소개
– 유동인구 중심좌표 데이터를 활용하여 QGIS에서 시각화 가능한 격자(SHP) 파일을 생성하기 위해 Python의 geopandas, shapely, pyproj를 사용합니다.
| geopandas | shapely | pyproj | |
| 주요 기능 | pandas 확장 공간데이터 처리 라이브러리 | 벡터형 공간객체 생성·연산 | 좌표계(CRS) 및 좌표 변환 |
| 활용 목적 | 공간 객체(Point, Polygon 등) 관리, 좌표계(CRS) 설정, SHP 파일 저장 등 | 중심좌표로부터 50×50m 정사각형 Polygon(격자) 생성에 사용 | UTM-K(EPSG:5179) 좌표계 정의 및 좌표계 변환 기능 제공 |
<사용 라이브러리 기능 및 활용 목적>
나. 버퍼 내 유동인구 추출 방법
– QGIS에서 수동으로 수행하던 공간 조인(Spatial Join) 작업을 Python으로 자동화한 코드입니다.
– 유동인구 데이터 중 특정 구역에 해당하는 점(포인트)만 선별하기 위해 두 가지 서로 다른 공간 데이터를 불러옵니다.
| INPUT_CSV = r”C:\…\유동인구데이터.csv” BUFFER_SHP = r”C:\…\버퍼_150.shp” df = pd.read_csv(INPUT_CSV, encoding=’euc-kr’) buffer_gdf = gpd.read_file(BUFFER_SHP) |
<데이터 불러오기>
– utmk_x, utmk_y 좌표값을 이용해 각각의 행(인구 데이터)을 점(Point) 형태로 변환하고 공간 연산을 위해 GeoDataFrame 객체로 만듭니다.
– 공간 연산(예: 포인트가 폴리곤 안에 포함되는지)을 정확히 수행하려면 두 데이터의 좌표계(CRS)가 반드시 같아야 하므로 버퍼 파일과 좌표계를 맞춥니다.
| geometry = [Point(xy) for xy in zip(df[‘utmk_x’], df[‘utmk_y’])] gdf = gpd.GeoDataFrame(df, geometry=geometry, crs=”EPSG:5179″) gdf = gdf.to_crs(buffer_gdf.crs) |
<공간 데이터 변환 및 좌표계 설정>
– 두 공간 데이터 간의 위치 관계를 비교해 겹치는 데이터만 결합하는 sjoin() 함수를 사용하여 포인트(유동인구 좌표)가 버퍼(폴리곤) 영역 내부에 포함되는 경우(‘within’)만 선택하도록 설정하여 추출합니다.
– 추출된 결과는 이후 분석이나 시각화를 위해 다시 UTM-K 좌표계(EPSG:5179) 로 복원 후 내보냅니다.
| gdf_in_buffer = gpd.sjoin(gdf, buffer_gdf, predicate=’within’) gdf_in_buffer = gdf_in_buffer.to_crs(“EPSG:5179″) gdf_in_buffer.to_csv(r”C:\…\추출한유동인구데이터.csv”, index=False, encoding=’euc-kr’) |
<공간 조인(Spatial Join) 수행>
– 공간 조인 수행 결과

<(전)버퍼 영역 추출하기 전 (후)버퍼 영역 추출한 결과>
| df = pd.read_csv(r”C:\…\추출한유동인구데이터.csv”, encoding=”euc-kr”) df = df.rename(columns={ ‘utmk_x’: ‘utmk_x’, ‘utmk_y’: ‘utmk_y’, ‘총이용객’: ‘pop_total’, }) |
<데이터 불러오기>
– shapely의 box() 함수를 이용하여 중심좌표를 기준으로 50m X 50m사각형 Polygon 객체를 생성합니다.
| crs = CRS(“EPSG:5179”) def make_square(x, y, size=50): half = size / 2 return box(x – half, y – half, x + half, y + half) df[‘geometry’] = df.apply(lambda row: make_square(row[‘utmk_x’], row[‘utmk_y’]), axis=1) |
<중심좌표를 기준으로 격자(Polygon) 생성>
– geopandas를 이용해 공간정보를 포함하는 GeoDataFrame으로 변환하고, 좌표계를 지정합니다.
– 최종적으로 생성된 격자형 공간데이터를 ESRI Shapefile 형식으로 내보냅니다.
| gdf = gpd.GeoDataFrame(df, geometry=’geometry’, crs=crs) gdf.to_file(r”C:\…\유동인구데이터(격자변환).shp”, driver=”ESRI Shapefile”) |
< ESRI Shapefile 내보내기>
– 격자 데이터 생성 결과

<(좌)격자 데이터 생성 전 (우)격자 데이터 생성 후>
3. 결론
위의 기술을 활용하여 “해충 기피제 분사기 신설을 위한 유동인구 분석” 및 “관광 트렌드 분석”을 수행하였습니다.
통신데이터 외에도 카드 매출 데이터 등 중심좌표를 보유한 다양한 데이터에 본 방식을 적용하여 격자 단위 공간 분석을 수행할 수 있으며, 지역별 인구 이동 특성, 소비 집중 지역, 관광지별 유입 분포 등 다양한 공간적 패턴도 도출할 수 있습니다.

<격자 기반 유동인구 밀도 시각화>