0. 왜 지금 R 공간 네트워크(Spatial Networks)인가?
물류 배송 최적화, 대중교통 노선 설계, 보행자 이동성 분석, 스마트 시티 인프라 평가 등 현대 데이터 사이언스에서 네트워크(Network)와 지리공간(Spatial Geography)의 결합은 필수적인 분석 역량입니다.
과거 R 언어의 공간 네트워크 분석은 다음과 같은 구조적 한계를 가지고 있었습니다: 1. sf로 도로망(LINESTRING)을 읽어온 뒤, 순수 그래프 패키지인 igraph 객체로 변환. 2. 그래프 상에서 최단경로를 계산한 후, 인덱스를 수동으로 추적하여 다시 sf 공간 객체로 복원. 3. 변환 단계마다 좌표와 노드 인덱스가 어긋나거나 코드가 장황해져 오류 발생 위험이 큼.
하지만 2024~2026년 현재, R의 공간 네트워크 생태계는 sfnetworks, dodgr, stplanr 3대 패키지를 중심으로 완전히 현대화되었습니다.
💡 현대 R 공간 네트워크의 3대 핵심 전략: *
sfnetworks:sf(공간)와tidygraph(그래프)가 결합된 단일 클래스로, 일반적인 네트워크 조작, 최단경로, 이소크론, 시각화의 표준. *dodgr(Distances on Directed Graphs in R): OpenStreetMap(OSM) 기반 수천~수만 개의 대규모 기점-종점(Many-to-Many OD) 거리 및 소요시간 행렬 고속 연산에 특화. *stplanr: 교통·운송 계획(Transport Planning) 패키지로 OSRM, GraphHopper 등 전문 외부 라우팅 엔진과의 연계 지원.
1. 공간 네트워크의 기본 개념과 데이터 모델
공간 네트워크(Spatial Network)는 그래프 이론(Graph Theory)의 위상학적 연결성과 지리정보시스템(GIS)의 실제 좌표 체계가 융합된 데이터 모델입니다.

1-1. 그래프 관점 (Graph Topology)
- 노드 (Nodes / Vertices): 교차로, 정류장, 건물 출입구, 시설물 등 이동의 분기점 및 출발·도착 지점.
- 엣지 (Edges / Links): 도로, 보행로, 자전거 전용도로, 철로, 하천 등 노드를 잇는 연결 선분.
- 방향성 (Directionality):
- 유향 그래프 (Directed): 일방통행 도로, 경사도에 따른 상향/하향 속도 차이 반영.
- 무향 그래프 (Undirected): 양방향 통행이 자유로운 일반 보행로 및 이면도로.
1-2. 지리공간 관점 (Spatial Attributes & Dual Weights)
- 실제 지리좌표계(CRS): 모든 노드와 엣지는 경위도(WGS84) 또는 투영좌표(EPSG:5179) 상의 물리적 좌표를 보유.
- 이중 가중치 (Dual Weights):
- 물리적 거리 가중치 (\(d\), meters): 엣지의 실제 선형 길이.
- 통행 시간 가중치 (\(t\), seconds): 도로별 제한 속도, 보행 속도(예: 4.5 km/h), 신호 대기 시간을 반영한 실질 이동 비용.
2. R 공간 네트워크 패키지 생태계 한눈에 보기
| 패키지 | 기반 아키텍처 | 핵심 기능 및 강점 | 주 사용처 |
|---|---|---|---|
| sfnetworks | sf + tidygraph (igraph) |
공간 기하학과 그래프 위상을 단일 객체로 통합, dplyr 문법 조작, 모핑(Morphing) |
표준 공간 네트워크 분석, 경로 탐색, 이소크론 시각화 |
| dodgr | C++ 고성능 B-heap Dijkstra | 대규모 OSM 도로망 자동 수집, 수만 개 OD 쌍의 초고속 거리/시간 행렬 계산 | 도시·국가 단위 대규모 OD 매트릭스, 접근성 평가 |
| stplanr | R 오픈소스 교통계획 | OSRM, GraphHopper 등 외부 고성능 라우팅 엔진 래핑, 교통 수요 모델링 | 지자체 교통 정책, 대중교통 경로 최적화 |
| cppRouting | 순수 C++ 다익스트라/A* | 초고속 라우팅 연산 엔진 | sfnetworks의 백엔드 연산 가속 |
3. [워크플로 1] sfnetworks: 공간 객체와 그래프의 완전한 결합
sfnetworks는 공간 데이터 프레임(sf)과 그래프 데이터(tidygraph)를 하나로 통합하여, activate() 함수를 통해 노드 테이블과 엣지 테이블을 dplyr 문법으로 자유롭게 조작할 수 있는 혁신적인 패키지입니다.

3-1. 패키지 로드 및 예제 데이터 변환
sfnetworks에 내장된 독일 뮌스터 인근 소도시 도로망 데이터인 roxel을 활용해 공간 네트워크 객체를 생성합니다.
# 1. 라이브러리 로드
library(sf)
library(sfnetworks)
library(tidygraph)
library(dplyr)
library(ggplot2)
options(scipen = 999) # 지수 표기 억제
# 2. 예제 도로망 데이터셋 로드
roxel_sf <- sfnetworks::roxel
# 3. 정밀한 거리 계산을 위해 미터 단위 투영 좌표계로 변환 (유럽 EPSG:3035)
roxel_proj <- st_transform(roxel_sf, 3035)
# 4. sf -> sfnetwork 객체로 변환
net <- as_sfnetwork(
roxel_proj,
directed = FALSE, # 일반 양방향 도로 가정
edges_as_lines = TRUE # 엣지를 LINESTRING 기하학으로 유지
)
print(net)3-2. activate() 인터페이스와 가중치(거리/시간) 부여
sfnetworks에서는 activate("nodes") 또는 activate("edges")를 사용하여 조작 대상을 명시적으로 전환합니다. edge_length() 함수는 투영 좌표계 기준의 실제 미터(m) 길이를 계산합니다.
# 1. 엣지 테이블 활성화 및 거리(m) 컬럼 추가
net <- net %>%
activate("edges") %>%
mutate(dist_m = edge_length())
# 2. 보행 속도(시속 4.5km) 기준 소요시간(초) 컬럼 추가
walk_speed_mps <- 4.5 * 1000 / 3600 # 1.25 m/s
net <- net %>%
activate("edges") %>%
mutate(time_s = as.numeric(dist_m) / walk_speed_mps)
# 노드 및 엣지 수 확인
net %>% activate("nodes") %>% as_tibble() %>% nrow()
net %>% activate("edges") %>% as_tibble() %>% nrow()3-3. 다익스트라(Dijkstra) 알고리즘 기반 최단경로 계산
st_network_paths() 함수를 사용하면 특정 노드 또는 임의의 지리 좌표(POINT) 사이의 최단 경로를 즉시 계산할 수 있습니다.
# 무작위로 출발 노드와 도착 노드 선택
set.seed(42)
node_ids <- sample(seq_len(igraph::vcount(net)), 2)
from_node <- node_ids[1]
to_node <- node_ids[2]
# 시간 가중치(time_s) 기준 최단경로 탐색
shortest_path <- st_network_paths(
net,
from = from_node,
to = to_node,
weights = "time_s" # dist_m 지정 시 최단거리 기준
)
print(shortest_path)
3-4. 최단 경로를 sf 객체로 추출하여 시각화
# 1. 최단 경로에 포함된 엣지 인덱스 추출
path_edge_ids <- shortest_path$edge_paths[[1]]
# 2. 해당 엣지만 필터링하여 sf 객체로 변환
route_sf <- net %>%
activate("edges") %>%
slice(path_edge_ids) %>%
st_as_sf()
# 3. ggplot2 레이어 시각화
ggplot() +
geom_sf(data = st_as_sf(net, "edges"), color = "grey80", linewidth = 0.4) +
geom_sf(data = route_sf, color = "#ef4444", linewidth = 1.2) +
theme_minimal() +
labs(
title = "Roxel Road Network: Shortest Path",
subtitle = paste0("Total Edges: ", length(path_edge_ids), " links")
)3-5. 기점-종점(OD) 비용 행렬 계산: st_network_cost()
다수의 출발지와 도착지 간의 통행시간 또는 거리 행렬을 일괄 계산합니다.
# 노드 1~5번에서 노드 6~10번까지의 5x5 이동 비용 행렬 계산
cost_matrix <- st_network_cost(
net,
from = 1:5,
to = 6:10,
weights = "time_s"
)
print(cost_matrix)
4. [워크플로 2] dodgr: 대규모 도시 도로망 고속 최단경로 연산
dodgr(Distances on Directed Graphs in R)는 도시 단위 이상의 수천~수만 개 좌표 쌍에 대해 OpenStreetMap 도로망을 내려받고, 고도로 최적화된 C++ B-heap 기반 다익스트라 엔진으로 수초 내에 OD 행렬을 계산합니다.
library(dodgr)
# 1. 특정 영역(BBOX)의 OpenStreetMap 도로망 다운로드
# seoul_bbox <- c(126.96, 37.55, 127.00, 37.58) # 서울 도심
# street_net <- dodgr_streetnet(bbox = seoul_bbox, expand = 0.05)
# 2. 이동 수단별(보행자/자전거/자동차) 도로망 가중치 자동 부여
# weighted_net <- weight_streetnet(street_net, wt_profile = "foot")
# 3. 임의의 100개 지점 간의 100x100 거리 행렬 고속 계산
# od_dist_matrix <- dodgr_distances(
# graph = weighted_net,
# from = sample_coords_from,
# to = sample_coords_to
# )5. [워크플로 3] stplanr: 교통 계획 및 외부 라우팅 엔진 연계
stplanr 패키지는 실제 지자체 교통 계획 수립 및 대중교통 배차 분석에 활용되며, OSRM(Open Source Routing Machine)이나 GraphHopper 같은 외부 라우팅 서버와 연동하여 실시간 도로 통행 규제와 회전 제한을 반영한 경로를 생성합니다.
library(stplanr)
# OSRM 공개 서버 또는 사설 도커(Docker) OSRM 서버 연동 예시
# Sys.setenv(OSRM_SERVER = "https://router.project-osrm.org/")
# Sys.setenv(OSRM_PROFILE = "foot") # 보행자 프로파일
# 두 공간 포인트 간의 실제 도로 경로 생성
# route_result <- route(from = start_sf, to = end_sf, route_fun = route_osrm)6. [실전 프로젝트] 대학 캠퍼스 보행 네트워크 및 이동성(Isochrone) 분석
실제 대학교(충남대학교 대덕캠퍼스)의 OpenStreetMap 데이터를 수집하여, 캠퍼스 보행 네트워크를 구축하고 주요 건물(중앙도서관) 기준의 5분·10분 도보 접근성(Isochrone Walkability Service Area)을 평가하는 실전 파이프라인입니다.

6-1. OSM 데이터 수집 및 GeoPackage(GPKG) 구축 파이프라인
osmdata 라이브러리를 활용해 캠퍼스 경계(boundary), 보행로(highway), 건물(building) 폴리곤을 수집하고, s2 위상 오류를 방지하며 단일 campus.gpkg 파일로 패키징합니다.
library(sf)
library(osmdata)
library(dplyr)
# 1. 평면 좌표계 설정 (한국 중부원점 EPSG:5186 또는 국가표준 EPSG:5179)
proj_crs <- 5179
sf_use_s2(FALSE) # GEOS 위상 엔진 사용
# 2. 캠퍼스 영역 BBOX 정의 (충남대학교 유성캠퍼스 일원)
cnu_bbox <- c(127.338, 36.363, 127.355, 36.375)
# 3. 보행로(highway) 벡터 데이터 쿼리
cnu_osm_highways <- opq(bbox = cnu_bbox) %>%
add_osm_feature(key = "highway") %>%
osmdata_sf()
campus_paths_sf <- cnu_osm_highways$osm_lines %>%
st_transform(proj_crs) %>%
select(osm_id, name, highway)
# 4. 건물(building) 벡터 데이터 쿼리
cnu_osm_buildings <- opq(bbox = cnu_bbox) %>%
add_osm_feature(key = "building") %>%
osmdata_sf()
campus_buildings_sf <- cnu_osm_buildings$osm_polygons %>%
st_transform(proj_crs) %>%
select(osm_id, name, building)
# 5. 단일 GeoPackage 파일로 저장
# st_write(campus_paths_sf, "campus_cnu.gpkg", layer = "paths", delete_layer = TRUE)
# st_write(campus_buildings_sf, "campus_cnu.gpkg", layer = "buildings", delete_layer = TRUE)6-2. 캠퍼스 보행 네트워크 분석 및 건물 간 최단 경로 탐색
# 1. 보행로 레이어로 sfnetwork 생성
campus_net <- as_sfnetwork(campus_paths_sf, directed = FALSE) %>%
activate("edges") %>%
mutate(dist_m = edge_length())
# 2. 가장 큰 연결 성분(Main Component)만 추출하여 고립 노드 제거
campus_net <- campus_net %>%
activate("nodes") %>%
mutate(comp = group_components()) %>%
filter(comp == 1) %>%
select(-comp)
# 3. 정문에서 중앙도서관까지의 최단 보행 경로 계산
# gate_node <- ...
# lib_node <- ...
# walk_path <- st_network_paths(campus_net, from = gate_node, to = lib_node, weights = "dist_m")7. 실무자를 위한 핵심 체크리스트 요약
📚 참고 문헌 및 공식 출처
| 구분 | 자료명 및 공식 사이트 | 주요 내용 | 바로가기 |
|---|---|---|---|
| R 공식 재단 | sfnetworks: Spatial Network Analysis in R (CRAN) | sf와 tidygraph를 융합한 공간 네트워크 클래스 공식 도큐멘테이션 | 공식 문서 |
| R 공식 재단 | dodgr: Distances on Directed Graphs in R (CRAN) | 대규모 OpenStreetMap 도로망 기반 고속 최단거리/시간 매트릭스 엔진 | 공식 가이드 |
| 오픈 연구소 | r-spatial: Spatial networks in R with sf and tidygraph | R 지리공간 네트워크 분석의 패러다임 전환 원문 연구 리포트 | 원문 포털 |
| 교통 패키지 | stplanr: Sustainable Transport Planning with R | 교통 계획, OSRM/GraphHopper 외부 라우팅 인터페이스 레퍼런스 | 공식 튜토리얼 |
| 오픈 서적 | Geocomputation with R: Chapter on Transport & Networks | R 기반 지리공간 교통 및 네트워크 분석 종합 교재 | 원문 도서 |