-
Notifications
You must be signed in to change notification settings - Fork 2
/
README.Rmd
348 lines (257 loc) · 15.6 KB
/
README.Rmd
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
---
output: github_document
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```
# bitSpatial <img src="man/figures/bitSpatial_logo.png" align="right" height="120" width="103.6"/>
## 설치하기
bitSpatial 패키지는 [GitHub](https://github.com/)으로부터 다음과 같이 설치합니다.
``` r
# install.packages("devtools")
devtools::install_github("bit2r/bitSpatial")
```
## 배경
지방자치 시대에 대한민국이 아닌 지역에 대한 경제, 사회, 문화 등의 이해는 중요한 사회과학적인 요소입니다. 그리고 지역에 대한 이해는 좀더 직관적인 시각화 방법이 유용합니다.
그러나 이러한 방법은 장미빛 청사진이 아닙니다. 데이터를 지역 기준으로 집계하고, 집계한 통계를 시각화하는 방법이 녹록치 않기 때문입니다.
### 1. 행정구역 체계의 일반화 이슈
현재 우리나라 행정구역 체계는 다음 그림과 같습니다. 행정 구역은 크게 1개의 특별시(서울), 6개의 광역시(부산, 대구, 인천, 광주, 대전, 울산), 6개의 도(경기, 충북, 충남, 전남, 경북, 경남), 1개의 특별자치시(세종), 3개의 특별자치도(강원, 전북, 제주)로 구성되어 있습니다.[^1]
[^1]: http://nationalatlas.ngii.go.kr/
```{r, echo=FALSE, out.width = "85%", fig.align='center', fig.cap="소스: http://nationalatlas.ngii.go.kr/pages/page_1217.php"}
knitr::include_graphics("man/figures/kor_hi_54-2.jpg")
```
삽화소스: [국토지리정보원 청소년을 위한 국가지집](http://nationalatlas.ngii.go.kr/pages/page_1217.php)
이를 기준으로 행정구역 체계를 일반화하기 위해서 광역시도 > 시군구 > 읍면동 레벨의 3단계 계층을 생각해볼 수 있습니다.
- 광역시도
- 특별시 + 특별자치시 + 특별자치도 + 광역시 + 도
- 시군구
- 시 + 군 + 구
- 읍면동
- 읍 + 면 + 동
그러나 광역시도 > 시군구 > 읍면동의 3단 계층 구조에서 다음의 예외 사항이 존재합니다.
- 세종특별 자치시의 구조
- 2단계 계층
- 광역시도 > 시군구 레벨 없음 > 읍면동
- 충청남도 천안시 동남구 신방동
- 4단계 계층
- 도 + 시 + 구 + 읍면동
- 인구가 팽창하는 도에 포함된 일부 시의 경우 (구) 레벨을 포함하기도 함
- 경기도 수원시, 경기도 성남시, 경기도 고양시 등
### 2. 행정구역 체계의 변화 이슈
행정구역 체계는 변화합니다. 다음 그림은 광역시도 레벨의 행정구역 체계 변경 히스토리입니다.
```{r, echo=FALSE, out.width = "85%", fig.align='center', fig.cap="소스: http://nationalatlas.ngii.go.kr/pages/page_1217.php"}
knitr::include_graphics("man/figures/kor_hi_54-1.jpg")
```
삽화소스: [국토지리정보원 청소년을 위한 국가지집](http://nationalatlas.ngii.go.kr/pages/page_1217.php)
지역에 대한 통계가 현황 분석을 목적으로 한다면 문제가 없겠지만, 시점별 통계의 변화를 살피는 추이분석을 수행할 경우에는 문제가 발생합니다.
행정구역 체계의 변경으로 인해서 과거의 통계를 현재의 행정구역에 매핑할 수 없는 경우가 있습니다.
그나마 광역시도와 시군구 레벨의 행정구역의 변경은 흔치 않지만, 읍면동 레벨(특히 행정동 기준)의 행정구역의 변경은 매우 잦게 발생합니다. 하나의 동이 여러 개의 동으로 분동되거나, 여러 동이 합동하여 하나의 구로 변합되거나 하는 사례가 많습니다.
### 3. 법정동이냐 행정동이냐 그것이 문제로다.
광역시도 > 시군구 > **읍면동** 레벨에서의 읍면동은 두 가지 기준이 있습니다.
- 법정동
- **법**으로 **정**한 **동**의 의미로, 법으로 정한 행정구역의 단위
- 1914년 시행된 행정구역 통폐합때 정한 것으로, 현재까지 거의 변동이 없음
- 행정동
- 행정능률, 주민편의에 의해 설정한 행정구역의 단위
- 인구수 기반으로 나뉘어지며 주민센터에서 관리하는 구역
- 편의에 따라 분할/병합 등의 변경 및 폐지가 발생함
문제는 법정동:행정동의 관계는 M:N의 관계로, 통계 집계에 있어서 상호 매핑하기 어렵기 때문에 하나의 집계 기준을 가져가야 한다는 점입니다.
- 법정동은 변동이 적기 때문에 법정동의 집계기준으로 가져가면 추이분석 등의 장점이 있지만,
- 공공 데이터에서 법정동 기준으로 배포하는 통계가 적습니다.
- 행정동은 변동이 많기 때문에 행정동의 집계기준으로 가져가면 추이분석 등의 단점이 있지만,
- 공공 데이터에서 행정동 기준으로 배포하는 통계가 많습니다.
- 많은 파생 통계가 인구통계 기반으로 작성되기 때문에 인구통계는 중요한 통계입니다.
### 4. 읍면동 행정구역 레벨 집계의 어려움
지번 주소에서 이제는 도로명 주소가 표준 주소 체계로 사용되고 있습니다. 그러나 우리가 집계해야할 지역기반의 Raw 데이터는 지번주소, 도로명주소가 혼용되어 있습니다. 과거의 통계를 무시하고 항상 현재 기준의 통계를 사용할 수 없으며, 경우에 따라서 현재 기준의 Raw 데이터가 과거 주소 체계로 배포되는 문제도 있습니다.
도로명 주소는 길게 이어진 도로를 기준으로 만들어진 체계입니다. 구역을 분할하는 기준이 아니어서, 어떤 도로는 여러 구역을 넘나들면 이어져 있기도합니다. 그래서 도로명 주소 정보로 행정동이나 법정동으로 집계하는 것은 그리 쉬운 작업은 아닙니다.
### 5. 비표준화된 관리 체계
정부에서 제공하는 공공 데이터는 한심스럽게도, 이러한 지역 체계의 표준이 없습니다. 일례로 행정안전부에서 관리하는 행정동 코드와 통계청에서 관리하는 행정동 코드 체계가 다릅니다. 그로므로 여러 공공 데이터를 통합하여 데이터를 분석할 때에는 데이터 수요자가 이 문제를 해결해야 합니다.
### 6. 공공재로서의 수치지도의 한계
지리정보는 국가분단이라는 안보의 특수성이 있기 때문에 중요하게 다뤄야하는 기밀일 수 있습니다. 그러나 행정구역 경계 수치지도의 경우에는 이와 무관한 정보로서 민간 및 학계의 연구를 위해서 안정적으로 공급되어야 합니다. 그러나 정부의나 공공 기관에서 배포하는 행정구역 경계 수치지도는 거의 제한적이고, 오류가 포함되어 있거나 행정구역 체계의 변화를 담지 못하고 있는 실정입니다. 변화하는 행정 구역체계에 따라 히스토리컬하게 배포하지 않습니다.
## 개요
`bitSpatial`은 통계지리정보(SGI; Statistical Geographic Information)를 개발을 지원하는 패키지로 광역시도 > 시군구 > 읍면동 레벨의 행정구역 경계 수치지도 기반으로 공공데이터를 집계하고, 이를 시각화하는 일련의 리소스를 제공합니다.
`bitSpatial`는 앞에서 제기한 이슈를 완벽하게 해결한 완벽한 솔루션은 아닙니다. 그러나 차선의 솔루션은 될 수 있습니다. 현재와 근접한 행정동 기준의 행정구역 경계 수치지도를 준비하였고, 여러 통계를 집적했습니다. 그리고 앞으로도 여러 통계를 추가해 나가려 합니다.
### 제공하는 리소스
#### 통계지리정보 생산을 위한 리소스
- 광역시도 > 시군구 > 읍면동 레벨의 **행정구역 경계 수치지도 제공**
- 수치지도를 sf 객체로 가공하여 제공
- 매년 6월 기준으로 배포
- 17 광역시도
- 250 시군구
- 3,528 읍면동
- **수치지도와 결합한 행정구역별로 집계된 통계**
- 40개 통계
- 인구통계, 초중고 학교 통계, 병원/약국 통계
- 집계 통계는 계속 추가할 예정
- 수치지도와 조인할 수 있는 집계된 통계
- 성별/연령대별 인구수
- 수치지도와 조인할 수 있는 위치정보 데이터
- 초중등학교 위치 데이터
- 약국/병원 위치 데이터
- 상가 위치 데이터
#### 지리 기반 연산을 위한 기능
- 위치 좌표 기반 연산
- 두 좌표의 거리 구하기
- 경위도 좌표계 위치정보의 좌표계 변환
- 지리기반 집계를 위한 메타
- 우편번호 행정동 매핑 데이터
- 위도/경도로 행정구역 코드와 이름 가져오기
#### SGI 시각화를 위한 기능
- 주제도 시각화
- 최적 지도 이미지 사이즈 계산
- map 시각화용 ggplot2 테마
### 리소스의 원천
- 수치지도
- 통계청의 [통계지리서비스](https://sgis.kostat.go.kr/)에서 배포하는 지역경계 수치지도
- 행정동 기준
- 매년 주기적으로 배포하는 장점으로 선정
- 매년 6월 기준으로 배포
- 통계 및 집계 데이터
- 인구통계
- 행정안전부의 주민등록 인구 통계
- https://jumin.mois.go.kr/index.jsp
- 초중고 학교 위치 정보
- 공공데이터포털의 전국초중등학교위치표준데이터
- https://www.data.go.kr/data/15021148/standard.do?recommendDataYn=Y
- 병원 및 약국 위치 정보
- 공공데이터 포털의 건강보험심사평가원_전국 병의원 및 약국 현황
- https://www.data.go.kr/data/15051059/fileData.do
- 상가 위치 정보
- 공공데이터 포털의 소상공인시장진흥공단_상가(상권)정보
- https://www.data.go.kr/data/15083033/fileData.do
## 주제도 그리기
sf 객체를 다룰 수 있는 R 사용자는 sf 객체로 제공하는 수치지도 정보와 데이터를 활용할 수 있겠으나, 익숙치 않는 사용자는 주제도 시각화 함수인 `thematic_map()` 함수를 사용하면 주제도를 그릴 수 있습니다.
이 함수의 원형은 다음과 같습니다.
```{r, eval=FALSE}
thematic_map(
zoom = c("mega", "cty", "admi")[1],
subset = NULL,
stat = NULL,
polygon = TRUE,
point = FALSE,
label = NULL,
col_cnt = 9,
palette = "YlOrRd",
line_col = "darkgray",
fill = "lightblue",
point_col = "blue",
title = NULL,
subtitle = NULL,
legend_pos = c("none", "right", "left", "bottom", "top"),
base_family = "NanumSquare"
)
```
### 줌 레벨별 시각화
광역시도 > 시군구 > 읍면동의 3단계 줌 레벨을 지원합니다.
`zoom` 인수로 줌 레벨을 지원합니다. 기본값인 `mega`가 광역시도 레벨이며, `cty`, `admi` 인수값으로 시군구, 읍면동 레벨의 주제도를 그릴 수 있습니다.
#### 광역시도별 인구분포
```{r, warning=FALSE, fig.height=7.48, fig.width=9.5, fig.align='center', message=FALSE}
library(bitSpatial)
thematic_map(stat = "인구수",
title = "광역시도별 인구분포 현황",
legend_pos = "right")
```
#### 시군구별 병원수 현황
```{r, warning=FALSE, fig.height=7.48, fig.width=8, fig.align='center'}
thematic_map(zoom = "cty",
stat = "병원수",
title = "시군구별 병원수 현황",
palette = "Blues")
```
특정 영역을 선택하려면 `subset` 인수를 사용합니다. 이 인수는 결과값이 logical인 R 표현식을 지원합니다.
다음은 수도원의 병원수 분포를 시각화합니다.
```{r, warning=FALSE, fig.height=4.3, fig.width=8, fig.align='center'}
thematic_map(zoom = "cty",
stat = "병원수",
subset = mega_nm %in% c("서울특별시", "경기도", "인천광역시"),
title = "시군구별 병원수 현황",
subtitle = "수도권 지역 (서울특별시, 경기도, 인천광역시)",
palette = "Blues")
```
#### 읍면동별 평균연령 현황
다음은 서울 양천구의 행정동별 평균연령 현황입니다. 양천구의 기하학적 모습이 마치 강아지와 닯았습니다.
```{r, warning=FALSE, fig.height=7.1, fig.width=8, out.width="70%", fig.align='center'}
thematic_map(zoom = "admi",
subset = mega_nm == "서울특별시" & cty_nm %in% "양천구",
stat = "age_mean",
label = "name",
title = "서울 양천구 인구통계 주제도",
subtitle = "동별 평균 연령 현황",
palette = "Purples",
legend_pos = "right")
```
### 기하학적 표현
기하학적으로 통계를 표현하는 방법은 3가지로 각각의 인수로 표현이 가능합니다. 한 주제도에 세 가지 모두 표현이 가능하지만 가독성이 떨어져서 한 가지만 표현하는 것을 권장합니다.
- 다각형의 그라데이션 색상
- `polygon`
- TRUE/FALSE로 지정
- 기본값은 TRUE
- 다각형 중심의 포인트 크기
- `point`
- TRUE/FALSE로 지정
- 기본값은 FALSE
- 다각형 중심에 숫자 라벨 표현
- `label`
- NULL은 미표현
- "name"
- 행정구역 이름
- "value"
- 통계 수치
- 기본값은 NULL
```{r, warning=FALSE, fig.height=8.7, fig.width=6, out.width="60%", fig.align='center'}
thematic_map(zoom = "admi",
subset = cty_nm %in% "노원구",
stat = "household",
polygon = FALSE,
point = TRUE, point_col = "Red",
label = "name",
line_col = "black", fill = "grey90",
title = "서울특별시 가구 분포",
subtitle = "노원구 동별 가구현황")
```
## 제공하는 정보
### 집계된 통계
`stats_info`에 패키지에서 제공하는 집계된 통계 현황이 있습니다. 통계 아이디와 이름이 있는데 모두 `thematic_map()` 함수에서 주제도를 그릴 때 통계 정보를 식별할 수 있는 `stat` 인수에 사용 가능합니다.
```{r, include=TRUE}
stats_info |>
gt::gt() |>
gt::as_raw_html()
```
### 위치 데이터
현재는 다음과 같은 위치 데이터를 제공합니다.
- 초중고등학교 위치정보
- 약국 위치정보
- 병원 위치정보
- 상가 위치정보
#### 주제도에 위치정보 병합
위치 데이터인 학교위치, 약국위치, 병원위치를 주제도에 매시업하여 시각화가 가능합니다.
```{r, warning=FALSE, fig.height=7.1, fig.width=8, fig.align='center'}
pos_school <- school |>
filter(mega_nm %in% "서울특별시") |>
filter(school_class %in% "초등학교") |>
st_as_sf(coords = c("lon", "lat"), crs = 4326)
ggplot() +
stat_density_2d(data = pos_school,
mapping = aes(x = purrr::map_dbl(geometry, ~.[1]),
y = purrr::map_dbl(geometry, ~.[2]),
fill = after_stat(density)),
geom = 'tile',
contour = FALSE,
alpha = 0.7) +
scale_fill_viridis_c(option = "viridis", direction = -1) +
geom_sf(data = cty |>
filter(mega_nm %in% "서울특별시"),
color = "grey30", fill = NA, linewidth = 0.8) +
geom_sf(data = pos_school, color = "blue", size = 0.5) +
xlim(126.75, 127.22) +
ylim(37.42, 37.71) +
labs(title = "서울특별시 초등학교 분포 현황",
subtitle = "출처: 공공데이터포털의 전국 초중등학교 위치 표준데이터") +
theme_custom_map()
```