R) 전처리 - 지리 좌표계(CRS) 변환

R) 전처리 - 지리 좌표계(CRS) 변환

대부분의 지리 데이터 처리는 WGS84 좌표계를 기준으로 한다. 한국 지도는 보통 TM좌표계를 사용하는데 이를 WGS84 좌표계로 변환하는 실습을 해본다.

개요

CRS(Coordinate Reference System)로 표기하기도 하는 지리 좌표계는 그 종류가 매우 많다. 각 위치의 지형지물을 정확하게 측량하기 위해서 국가별 지역별 다양한 지리 좌표계가 제안되었고 사용되고 있다. 그 이유가 지구는 완전한 구도 아니고 하나의 타원체로 정의할 수 없다보니 각 지역(지점) 기준 가장 알맞는 타원체와 관련된 정보를 기반으로 개발한 지리 좌표계를 사용할 뿐이다. 하지만 각 지역에서 측량할 때 잘 들어맞지만, 다른 지역의 측량할 때는 그 지역에 맞는 좌표계로 변환해야하는 등 불편함이 많다. 특히 전 세계의 지리를 한 번에 분석하고 처리하기 위해서는 어느 정도 오차를 감수하고 사용할 수 있는 통일된 좌표계가 필요하기 마련이다. 그리하여 1950년대 미국 국방부에서 발표한 것이 바로 WGS60 좌표계이다. 이렇게 예전에는 군대 정도만 이런 통일된 좌표계가 필요했다면, 이제는 전 세계 지도를 서비스하는 사업자와 전지구 데이터를 다루는 분석가 또한 이런 좌표 체계의 수요자라고 할 수 있겠다. 그래서 조금씩 기존 WGS 좌표계를 개선하여 오늘날에 범용적으로 사용하는 것이 바로 WGS84(World Geodetic System 1984, EPSG:4326) 좌표계인데 한국에서 많이 사용하는 것은 TM좌표계라서 이를 WGS84로 변환하는 작업이 필요하고 이를 다루고자 한다.

WGS84 좌표계 관련 자세한 문서를 보고자 한다면 위키피디아의 World Geodetic System을 참고하도록 하자.

준비

여기에서 사용하는 지도 데이터는 시군구 기준의 행정경계구역이 표기된 자료를 활용하며 한국 행정경계지도 시각화 포스팅에서 사용하는 것과 같으니 참고하도록 하자.

여기에서 사용하는 지하철역 위치 데이터는 서울 열린데이터 광장 에서 제공하는 서울특별시 노선별 지하철역 정보(신규)를 추가 가공한 데이터를 사용한다.
서울특별시 노선별 지하철역 정보
seoul_subway_line_2_geocoded.csv 다운받기 [클릭]

사용할 패키지와 데이터를 불러오자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
library("rgdal")
library("ggplot2")
map = readOGR("TL_SCCO_SIG.shp")
slotNames(map)
## [1] "data" "polygons" "plotOrder" "bbox" "proj4string"

map@polygons[[1]]@Polygons[[1]]@coords[1:4, ]
## [,1] [,2]
## [1,] 1007462 2008949
## [2,] 1007512 2008902
## [3,] 1007698 2008919
## [4,] 1007797 2008978

df_subway = read.csv("seoul_subway_line_2_geocoded.csv")
head(df_subway)
## CD stn_nm_kr stn_nm_en line_no
## 1 200 까치산 Kkachisan 02호선
## 2 201 시청 City Hall 02호선
## 3 202 을지로입구 Euljiro 1(il)-ga 02호선
## 4 203 을지로3가 Euljiro 3(sam)-ga 02호선
## 5 204 을지로4가 Euljiro 4(sa)-ga 02호선
## 6 205 동대문역사문화공원 Dongdaemun History Culture Park 02호선
## CD_ext loop order lon lat
## 1 234-4 0 0 126.8467 37.53177
## 2 201 1 1 126.9769 37.56570
## 3 202 1 2 126.9827 37.56607
## 4 203 1 3 126.9911 37.56629
## 5 204 1 4 126.9977 37.56662
## 6 205 1 5 127.0090 37.56568

변환

앞에서 불러온 지도데이터의 좌표계를 확인하면 다음과 같다.

1
2
3
4
map@proj4string
## CRS arguments:
## +proj=tmerc +lat_0=38 +lon_0=127.5 +k=0.9996 +x_0=1000000
## +y_0=2000000 +ellps=GRS80 +units=m +no_defs

“proj4string” 슬롯에 명시된 CRS는 폴더에 있는 4개의 파일 중 prj 확장자 파일에 있는 내용이 처리된 것이다.
지도데이터 파일

이제 CRS 정보가 있는 객체를 생성하고(꼭 리스트 객체가 아니어도 가능) spTransform() 함수를 사용한다. 이 때 해당 함수의 “CRSobj” 인자에 변환 대상이 되는 좌표계 정보를 입력하면 변환이 완료된다.

1
2
3
4
5
6
7
8
9
10
11
12
ls_crs = list(wgs84 = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")

map = spTransform(map, CRSobj = CRS(ls_crs$wgs84))
map@proj4string
## CRS arguments: +proj=longlat +datum=WGS84 +no_defs

map@polygons[[1]]@Polygons[[1]]@coords[1:4, ]
## [,1] [,2]
## [1,] 127.5851 38.08062
## [2,] 127.5857 38.08020
## [3,] 127.5878 38.08035
## [4,] 127.5889 38.08088

얼핏 보면 제대로 변환이 된 것 같지만 혹시 모르니 지도 시각화를 통해 다시 한 번 확인해보도록 하자.


확인

변환한 객체와 지하철 2호선 역 위치 정보를 활용하여 시각화해보자. 먼저 서울 지역만 추출하는 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
df_map_data = map@data
head(df_map_data, 2)
## SIG_CD SIG_ENG_NM SIG_KOR_NM
## 0 42110 Chuncheon-si 춘천시
## 1 42130 Wonju-si 원주시

df_map_data[, "id"] = (1:nrow(df_map_data)) - 1
df_map_data[, "SIDO_CD"] = as.numeric(substr(df_map_data$SIG_CD, start = 1, stop = 2))
head(df_map_data, 2)
## SIG_CD SIG_ENG_NM SIG_KOR_NM id SIDO_CD
## 0 42110 Chuncheon-si 춘천시 0 42
## 1 42130 Wonju-si 원주시 1 42

id_seoul = df_map_data[df_map_data$SIDO_CD == 11, "id"]

df_map = fortify(map)
head(df_map)
## long lat order hole piece id group
## 1 127.5851 38.08062 1 FALSE 1 0 0.1
## 2 127.5857 38.08020 2 FALSE 1 0 0.1
## 3 127.5878 38.08035 3 FALSE 1 0 0.1
## 4 127.5889 38.08088 4 FALSE 1 0 0.1
## 5 127.5903 38.08060 5 FALSE 1 0 0.1
## 6 127.5906 38.08053 6 FALSE 1 0 0.1

df_map_seoul = df_map[df_map$id %in% id_seoul, ]
head(df_map_seoul)
## long lat order hole piece id group
## 608458 127.0086 37.58047 1 FALSE 1 140 140.1
## 608459 127.0087 37.58045 2 FALSE 1 140 140.1
## 608460 127.0088 37.58044 3 FALSE 1 140 140.1
## 608461 127.0089 37.58042 4 FALSE 1 140 140.1
## 608462 127.0091 37.58039 5 FALSE 1 140 140.1
## 608463 127.0092 37.58039 6 FALSE 1 140 140.1

좌표계 변환된 서울지역 행정경계지도를 그려보자.

1
2
3
4
5
6
7
ggplot(data = df_map_seoul,
aes(x = long, y = lat,
group = group)) +
geom_polygon(fill = "#FFFFFF",
color = "#000000",
size = 1.2) +
theme_bw()

서울지역 행정경계지도 - 시군구

이제 2호선 지하철 역 정보를 얹어보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
ggplot() + 
geom_polygon(data = df_map_seoul,
aes(x = long, y = lat,
group = group),
fill = "#FFFFFF",
color = "#000000",
size = 1.2) +
geom_point(data = df_subway,
aes(x = lon, y = lat),
color = ifelse(df_subway$stn_nm_kr == "사당",
"#FF0000", "#00AA00"),
size = 5) +
theme_bw()

서울지역 행정경계지도 - 시군구 + 2호선

여기서 사당역만 빨간색으로 표기했는데 사당역이 관악구/서초구/동작구의 경계지점에 걸쳐있어 사당역이 각 행정구역의 경계지점에 있다면 좌표변환이 성공적으로 되었다고 판단할 수 있을 것이다. 다음은 카카오맵에서 확인한 사당역 인근 지도이며 핑크색 실선이 관악구 경계를 표기하고 있는 상태이다.
사당역 인근 지도

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×