- 개요
프로젝트 목표를 세웠으면 보통 가장 먼저 해야 할 일은 데이터 수집 계획을 세우는 것입니다.
이번 포스트에서는 데이터를 수집하고 확인을 해보겠습니다.
데이터를 읽고 정제하는 과정에는 python의 pandas 라이브러리를 주로 사용하고,
folium 라이브러리로 데이터를 시각화하겠습니다.
- 데이터 수집
제 목표는 영등포 타임스퀘어 3번 게이트까지 한 번에 버스를 타고 갈 수 있는 지역이 어디인가?입니다.
이 목표를 어떻게 이룰지 고민하면 필요한 자료를 알 수 있습니다.
목표를 달성하기 위해서는 아래의 질문의 답을 고민하면 됩니다.
Q1. 영등포 타임스퀘어 3번 게이트 근처의 버스 정류장은?
- 버스 정류소의 위치 자료가 필요
Q2. 근처 버스 정류장에 멈추는 버스 번호는?
- 버스 정류장에 멈추는 버스 자료 필요
Q3. 위의 버스가 멈추는 모든 버스 정류장은?
- 특정 버스가 경유하는 버스 정류장 자료 필요
Q4. 버스 정류장의 지역은?
- 버스 정류장의 좌표 필요, 나중에 지역으로 시각화할 생각이므로 지역을 그릴 수 있는 shp 자료 필요
요약하자면 버스 노선과 버스 정류소 데이터와 지역 경계 데이터가 필요합니다.
- 버스 노선, 버스 정류소 데이터
국가교통 오픈마켓 사이트에서 서울 교통수단 이동데이터를 받으면 그 안에 여러 파일 중 버스 노선, 버스 정류소 데이터가 있습니다.

관련 데이터를 압축해서 올립니다(2023년 자료라 현재와 다를 수 있음).
파일과 필요한 칼럼에 대해 설명하겠습니다.
TBIS_MS_ROUTE.csv는 버스 ID와 버스 이름을 매칭하기 위해 필요한 데이터로 ROUTE_ID는 버스 ID, ROUTE_NM은 버스의 한글/숫자 이름입니다.
TBIS_MS_ROUTE_NODE.csv는 버스가 경유하는 정류소에 대한 정보가 있으며 ROUTE_ID는 버스 ID, STTN_ID는 버스 정류소 ID, STTN_SN은 버스가 들리는 정류서 순서입니다.
마지막으로 TBIS_MS_STTN.csv는 버스 정류소에 대한 데이터로 STTN_ID는 정류소 ID, STTN_NM은 정류소 이름, STTN_NO는 버스 정류소 번호(ID와 다르고, 네이버 지도 같은 곳에 나오는 번호임), CRDNT_X는 경도, CRDNT_Y는 위도입니다.
참고로 TBIS_MS_STTN.csv는 ,와 띄어쓰기 오류가 있는 것으로 보여 제가 수정을 했습니다.
지역 경계 자료는 GEOSERVICE-WEB에서 다운로드 받았습니다.
이건 해당 서비스에서 특정 포인트를 차감(공짜 포인트로 받으면 됨)하는 식으로 받는 것이라 마음대로 데이터를 올리기 애매해서 따로 데이터를 올리지는 않겠습니다.
경계 데이터는 아래처럼 생겼고, EMD_CD는 읍면동 코드, EMD_ENG_NM은 영어 이름, EMD_KOR_NM는 한글 이름입니다. geometry를 보면 우리가 아는 위경도가 아니라 다른 좌표계이므로 나중에 변환해줘야합니다.

- 데이터 확인: 버스 데이터

타임스퀘어 근처 버스 정류소에서 660번 버스의 정류소를 확인하겠습니다.
import pandas as pd
fn = r'C:\Users\zerot\Desktop\python\busVisSystem\metadata\TBIS_MS_ROUTE_NODE.csv'
df_rn = pd.read_csv(fn, encoding='utf-8-sig')
fn = r'C:\Users\zerot\Desktop\python\busVisSystem\metadata\TBIS_MS_STTN.csv'
df_s = pd.read_csv(fn, encoding='utf-8-sig')
fn = r'C:\Users\zerot\Desktop\python\busVisSystem\metadata\TBIS_MS_ROUTE.csv'
df_r = pd.read_csv(fn, encoding='utf-8-sig')
target_routeId = df_r['ROUTE_ID'][df_r['ROUTE_NM']=='660'].tolist()[0]
print(target_routeId)# 결과: 11600004
# 600번 버스가 경유하는 버스 정류소를 list로 저장
stn_list = df_rn['STTN_ID'][df_rn['ROUTE_ID']== target_routeId].tolist()
# stn_list에는 STTN_ID만 있으므로 위도, 경도 정보를 알기위해 df_s와 merge함
df = pd.DataFrame({'STTN_ID': stn_list})
df_merged = pd.merge(df, df_s, how='left', on='STTN_ID')
600번 버스가 지나가는 버스 정류소를 df_merged에 저장했습니다.
import folium
m = folium.Map(location=[df_merged['CRDNT_Y'].mean(),
df_merged['CRDNT_X'].mean()], zoom_start=12)
for idx, row in df_merged.iterrows():
folium.CircleMarker(
location=[row['CRDNT_Y'], row['CRDNT_X']], # (lat, lon)
radius=3, # 반경 크기
color="blue", # 원의 색상
fill=True, # 채우기 여부
fill_color="blue", # 채우기 색상
fill_opacity=0.7, # 채우기 투명도
popup=f"Calc:({idx})" # 마커를 클릭했을 때 표시될 텍스트
).add_to(m)
m

제가 그린 660번 경유 버스 정류소 위치에 네이버 지도의 660번 버스 노선을 비교하면 잘 그린 것 같습니다.
버스 데이터는 큰 문제가 없는 것 같습니다.
- 데이터 확인: 지역 경계
읍면동 경계를 간단하게 그리겠습니다.
import geopandas as gpd
fn = r'C:\Users\zerot\Desktop\python\busVisSystem\data\읍면동\emd.shp'
gdf = gpd.read_file(fn, encoding='cp949')
gdf.plot()

자료에는 문제가 없는 것 같으니 다음 포스트에서는 영등포 타임스퀘어 3번 게이트에 버스로 한 번에 갈 수 있는 지역을 시각화하겠습니다.
'프로젝트 > 버스 한 번으로 특정 지역에 갈 수 있는 지역 찾기' 카테고리의 다른 글
| [특정 지역에 버스 한 번 타고 갈 수 있는 지역 찾기] 3. 버스 정류장이 속한 지역 찾기: geopandas.sjoin() (0) | 2025.05.12 |
|---|---|
| [특정 지역에 버스 한 번 타고 갈 수 있는 지역 찾기] 2. 버스 정류장, 버스 정류장에 정거하는 버스 및 이 버스의 정류장 찾기 (0) | 2025.05.10 |
| [특정 지역에 버스 한 번 타고 갈 수 있는 지역 찾기] 0. 목표 설정 (0) | 2025.05.07 |
