'ggmap'을 이용해서 대구 메트로 시각화하기 - 1일차
'ggmap'을 이용해서 대구 메트로 시각화하기 - 1일차
목적
대구 메트로 상하차 정보가 인터넷에 공개되어있는데, 이를 기반으로 지도에 시각화해보면, 어떤 통찰(인사이트)를 얻을 수 있지 않을까 하는 생각이 들어서 해보게 되었다.
- 메트로, 시내버스, 택시정보 등등을 하나하나 시각화하고 이를 종합할 수 있다면, 대구 교통량이 어떤지 뿐만 아니라, 더 나아가서,
- 대구 대중교통체계가 잘 작동하고 있는지,
- 어떤 곳이 교통 취약지역인지,
- 어떤 곳이 교통이 좋은지,
- 어떻게 보강하는게 좋을 것인지 등을 고민할 수 있는 여지가 생긴다고 생각한다.
혹은 부동산?
혹은 정책평가?
필요한 패키지
tidyverse
,reshape2
,ggmap
library(tidyverse)
## ─ Attaching packages ────────────────────────────── tidyverse 1.2.1 ─
## ✔ ggplot2 2.2.1 ✔ purrr 0.2.5
## ✔ tibble 1.4.2 ✔ dplyr 0.7.7
## ✔ tidyr 0.8.1 ✔ stringr 1.3.0
## ✔ readr 1.1.1 ✔ forcats 0.3.0
## ─ Conflicts ─────────────────────────────── tidyverse_conflicts() ─
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
library(reshape2)
##
## Attaching package: 'reshape2'
## The following object is masked from 'package:tidyr':
##
## smiths
library(ggmap)
데이터
전국도시철도역사정보표준데이터.csv ("df_역"이라 명명)
데이터 정보
df_역 <- read.csv("../Original_Data/전국도시철도역사정보표준데이터.csv", fileEncoding = "CP949")
df_역 %>% head(.)
## 역번호 역사명 노선번호 노선명 영문역사명 한자역사명
## 1 115 설화명곡 S2701 대구 도시철도 1호선 SeolhwaMyeonggok 舌化椧谷
## 2 116 화원 S2701 대구 도시철도 1호선 Hwawon 花園
## 3 117 대곡 S2701 대구 도시철도 1호선 Daegok 大谷
## 4 118 진천 S2701 대구 도시철도 1호선 Jincheon 辰泉
## 5 119 월배 S2701 대구 도시철도 1호선 Wolbae 月背
## 6 120 상인 S2701 대구 도시철도 1호선 Sangin 上仁
## 환승역구분 환승노선번호 환승노선명 역위도 역경도
## 1 일반역 35.79872 128.4893
## 2 일반역 35.80436 128.5004
## 3 일반역 35.80950 128.5104
## 4 일반역 35.81383 128.5204
## 5 일반역 35.81628 128.5284
## 6 일반역 35.81897 128.5357
## 운영기관명 역사도로명주소
## 1 대구광역시 대구도시철도공사 대구광역시 달성군 화원읍 비슬로 2476
## 2 대구광역시 대구도시철도공사 대구광역시 달성군 화원읍 비슬로 지하2600
## 3 대구광역시 대구도시철도공사 대구광역시 달서구 비슬로 지하2718 (대곡동)
## 4 대구광역시 대구도시철도공사 대구광역시 달서구 월배로 지하76 (진천동)
## 5 대구광역시 대구도시철도공사 대구광역시 달서구 월배로 지하143 (진천동)
## 6 대구광역시 대구도시철도공사 대구광역시 달서구 월배로 지하223 (상인동)
## 역사전화번호 데이터기준일자 제공기관코드 제공기관명 X
## 1 053-643-2674 2018-02-21 B552109 대구도시철도공사 NA
## 2 053-643-5125 2018-02-21 B552109 대구도시철도공사 NA
## 3 053-644-7723 2018-02-21 B552109 대구도시철도공사 NA
## 4 053-642-7723 2018-02-21 B552109 대구도시철도공사 NA
## 5 053-642-7732 2018-02-21 B552109 대구도시철도공사 NA
## 6 053-642-7745 2018-02-21 B552109 대구도시철도공사 NA
이 데이터셋은 역 정보를 담고 있다.
지도에 표시하려면 역의 위치가 필요해서 찾게 되었다.
대구도시철도공사_일별시간별승하차인원_20171231.csv ("df_승하차인원"이라 명명)
데이터 정보
df_승하차인원 <- read.csv("../Original_Data/대구도시철도공사_일별시간별승하차인원_20171231.csv", fileEncoding = "CP949")
df_승하차인원 %>% head(.)
## 월 일 역번호 역명 승하 X05.06 X06.07 X07.08 X08.09 X09.10 X10.11
## 1 1 1 1150 설화명곡 승차 22 37 61 111 167 201
## 2 1 1 1150 설화명곡 하차 1 65 38 68 79 79
## 3 1 1 1160 화원 승차 15 25 54 102 144 149
## 4 1 1 1160 화원 하차 1 42 50 48 85 110
## 5 1 1 1170 대곡 승차 46 57 86 137 243 282
## 6 1 1 1170 대곡 하차 1 145 73 106 123 126
## X11.12 X12.13 X13.14 X14.15 X15.16 X16.17 X17.18 X18.19 X19.20 X20.21
## 1 239 296 307 288 270 216 192 138 125 87
## 2 79 137 125 120 166 163 183 217 194 126
## 3 218 211 238 240 225 195 218 135 90 66
## 4 138 102 154 162 228 212 221 169 159 129
## 5 314 330 460 382 354 323 351 215 128 129
## 6 145 179 192 207 319 370 398 477 333 357
## X21.22 X22.23 X23.24 일계
## 1 56 47 7 2867
## 2 152 116 69 2177
## 3 50 28 13 2416
## 4 151 121 95 2377
## 5 101 60 11 4009
## 6 324 272 123 4270
이 데이터 셋은 날짜별, 시간별 대구 메트로 승차자와 하차자 수를 포함하고 있다.
이를 수치들을 잘 한 번 지도에 표시해보고자 한다.
데이터 전처리
df_역에서 대구 메트로 정보만 가져오기.
- 먼저 데이터 살펴보자.
dim(df_역) # 행과 열 수 보기
## [1] 262 18
summary(df_역) # 기초통계량 보기
## 역번호 역사명 노선번호 노선명
## 115 : 3 반월당 : 2 S2601 :40 부산도시철도 2호선 :43
## 116 : 3 중앙로 : 2 S2602 :38 부산도시철도 1호선 :40
## 117 : 3 가야역 : 1 S2701 :32 대구 도시철도 1호선:32
## 118 : 3 각산 : 1 S2703 :30 대구 도시철도 3호선:30
## 119 : 3 갈마 : 1 S2702 :29 대구 도시철도 2호선:29
## 101 : 2 감삼 : 1 S3001 :22 대전도시철도 1호선 :22
## (Other):245 (Other):254 (Other):71 (Other) :66
## 영문역사명 한자역사명 환승역구분 환승노선번호
## Banwoldang: 2 없음 : 7 일반역:243 :243
## City Hall : 2 : 2 환승역: 19 S2602+S2603: 2
## Deokcheon : 2 南山 : 2 S2603+S2602: 2
## Dongnae : 2 德川 : 2 S1101+L4101: 1
## Guam : 2 東萊 : 2 S2601+S2602: 1
## Jungangno : 2 蓮山 : 2 S2601+S2603: 1
## (Other) :250 (Other):245 (Other) : 12
## 환승노선명 역위도
## :243 Min. :35.05
## 부산도시철도 2호선+부산도시철도 3호선 : 2 1st Qu.:35.16
## 부산도시철도 3호선+부산도시철도 2호선 : 2 Median :35.31
## 대구 도시철도 1호선 + 대구 도시철도 2호선: 1 Mean :35.66
## 대구 도시철도 1호선 + 대구 도시철도 3호선: 1 3rd Qu.:35.87
## 대구 도시철도 2호선 + 대구 도시철도 1호선: 1 Max. :37.75
## (Other) : 12
## 역경도 운영기관명
## Min. :126.8 광주광역시 도시철도공사 : 20
## 1st Qu.:128.5 대구광역시 대구도시철도공사: 91
## Median :128.7 대전광역시 도시철도공사 : 22
## Mean :128.5 부산교통공사 :114
## 3rd Qu.:129.0 인천교통공사 : 15
## Max. :129.2
##
## 역사도로명주소 역사전화번호
## 대구광역시 중구 달구벌대로 지하2100 (덕산동): 2 031-820-1000: 15
## 부산광역시 동래구 아시아드대로 지하 232 : 2 053-640-7381: 6
## 부산광역시 부산진구 중앙대로 지하 730 : 2 053-640-7431: 6
## 부산광역시 북구 금곡대로 지하 14 : 2 053-640-7521: 6
## 부산광역시 수영구 수영로 지하 677 : 2 053-640-7581: 6
## 부산광역시 연제구 중앙대로 지하 1101 : 2 053-640-7611: 6
## (Other) :250 (Other) :217
## 데이터기준일자 제공기관코드 제공기관명
## 2018-01-30:114 3820000: 15 경기도 의정부시 : 15
## 2018-02-20: 22 B551232: 20 광주광역시도시철도공사: 20
## 2018-02-21: 91 B551542:114 대구도시철도공사 : 91
## 2018-06-25: 15 B551918: 22 대전광역시도시철도공사: 22
## 2018-08-16: 20 B552109: 91 부산교통공사 :114
##
##
## X
## Mode:logical
## NA's:262
##
##
##
##
##
$노선명
을 보면 대구 외에도 부산, 대전 등등 전국의 메트로가 다 같이 있는 데이터임을 알 수 있다.$노선명
을 이용해서 대구 메트로 정보만 선택하되,$역번호
,$역사명
,$역위도
,$역경도
는 필요하니 남기고, 나머지는 필요할 것 같지 않으니 없애자.
df_대구메트로역 <- df_역 %>%
select(., 노선명, 역번호, 역사명, 역위도, 역경도) %>% # 남길 열 선택
filter(., substr(노선명,1,2) == "대구") # $노선명 의 앞 2자리가 대구면 선택한다.
df_대구메트로역 %>% dim(.)
## [1] 91 5
- 행 수가 91인 걸로 보아, 91개 역 모두 선택됐음을 알 수 있다.
df_대구메트로역 %>% head(.)
## 노선명 역번호 역사명 역위도 역경도
## 1 대구 도시철도 1호선 115 설화명곡 35.79872 128.4893
## 2 대구 도시철도 1호선 116 화원 35.80436 128.5004
## 3 대구 도시철도 1호선 117 대곡 35.80950 128.5104
## 4 대구 도시철도 1호선 118 진천 35.81383 128.5204
## 5 대구 도시철도 1호선 119 월배 35.81628 128.5284
## 6 대구 도시철도 1호선 120 상인 35.81897 128.5357
df_대구메트로역 %>% tail(.)
## 노선명 역번호 역사명 역위도 역경도
## 86 대구 도시철도 3호선 336 어린이회관 35.84521 128.6245
## 87 대구 도시철도 3호선 337 황 금 35.83911 128.6240
## 88 대구 도시철도 3호선 338 수성못 35.83136 128.6232
## 89 대구 도시철도 3호선 339 지 산 35.82517 128.6319
## 90 대구 도시철도 3호선 340 범 물 35.82084 128.6401
## 91 대구 도시철도 3호선 341 용 지 35.81827 128.6465
$역사명
의 형식이 띄어쓰기가 돼있거나 안 돼있거나 제각각인 점이 아쉽다.
df_승차자인원을 조금 더 다루기 쉬운 형태로 정리하기.
- 먼저 데이터를 살펴보자.
names(df_승하차인원) # 열 이름 목록
## [1] "월" "일" "역번호" "역명" "승하" "X05.06" "X06.07"
## [8] "X07.08" "X08.09" "X09.10" "X10.11" "X11.12" "X12.13" "X13.14"
## [15] "X14.15" "X15.16" "X16.17" "X17.18" "X18.19" "X19.20" "X20.21"
## [22] "X21.22" "X22.23" "X23.24" "일계"
summary(df_승하차인원$역번호)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1150 1370 2290 2268 3190 3410
- 역 번호형식이
df_역
과는 다르다. 뒤에 0 하나가 더 붙은 듯 하다. 짚고 넘어가자.
table(일 = df_승하차인원$일, 월 = df_승하차인원$월)
## 월
## 일 1 2 3 4 5 6 7 8 9 10 11 12
## 1 182 182 182 182 182 182 182 182 182 182 182 182
## 2 182 182 182 182 182 182 182 182 182 182 182 182
## 3 182 182 182 182 182 182 182 182 182 182 182 182
## 4 182 182 182 182 182 182 182 182 182 182 182 182
## 5 182 182 182 182 182 182 182 182 182 182 182 182
## 6 182 182 182 182 182 182 182 182 182 182 182 182
## 7 182 182 182 182 182 182 182 182 182 182 182 182
## 8 182 182 182 182 182 182 182 182 182 182 182 182
## 9 182 182 182 182 182 182 182 182 182 182 182 182
## 10 182 182 182 182 182 182 182 182 182 182 182 182
## 11 182 182 182 182 182 182 182 182 182 182 182 182
## 12 182 182 182 182 182 182 182 182 182 182 182 182
## 13 182 182 182 182 182 182 182 182 182 182 182 182
## 14 182 182 182 182 182 182 182 182 182 182 182 182
## 15 182 182 182 182 182 182 182 182 182 182 182 182
## 16 182 182 182 182 182 182 182 182 182 182 182 182
## 17 182 182 182 182 182 182 182 182 182 182 182 182
## 18 182 182 182 182 182 182 182 182 182 182 182 182
## 19 182 182 182 182 182 182 182 182 182 182 182 182
## 20 182 182 182 182 182 182 182 182 182 182 182 182
## 21 182 182 182 182 182 182 182 182 182 182 182 182
## 22 182 182 182 182 182 182 182 182 182 182 182 182
## 23 182 182 182 182 182 182 182 182 182 182 182 182
## 24 182 182 182 182 182 182 182 182 182 182 182 182
## 25 182 182 182 182 182 182 182 182 182 182 182 182
## 26 182 182 182 182 182 182 182 182 182 182 182 182
## 27 182 182 182 182 182 182 182 182 182 182 182 182
## 28 182 182 182 182 182 182 182 182 182 182 182 182
## 29 182 0 182 182 182 182 182 182 182 182 182 182
## 30 182 0 182 182 182 182 182 182 182 182 182 182
## 31 182 0 182 0 182 0 182 182 0 182 0 182
갯수를 보니 입력이 누락된 날짜나 누락된 역은 없다.
- 데이터 가공 방향
$일계
를 제거하고,- reshape2::melt를 써서 wide format의 데이터를 long format으로 바꾸고,
- "X05.06", "X06.07" 등등을 "05-06", "06-07" 등등으로 바로잡자.
- 역번호에 뒤에 0을 떼자. ( 앞에서 가공한 데이터와 합치기 위함.)
df_승하차_melted <- df_승하차인원 %>%
select(., -일계) %>% # 1. $일계 제거
melt(.,id.vars = c("월", "일", "역번호", "역명", "승하"),
variable.name = "시간", value.name = "인원") %>% # 2. melt 사용
mutate(., 시간 = paste(substr(시간,2,3), "-", substr(시간,5,6), sep="")) %>% # 3. 시간 바로잡기
mutate(., 역번호 = paste(substr(역번호, 1, 3))) # 4. 역번호 뒤에 0 떼기
df_승하차_melted %>% head(.)
## 월 일 역번호 역명 승하 시간 인원
## 1 1 1 115 설화명곡 승차 05-06 22
## 2 1 1 115 설화명곡 하차 05-06 1
## 3 1 1 116 화원 승차 05-06 15
## 4 1 1 116 화원 하차 05-06 1
## 5 1 1 117 대곡 승차 05-06 46
## 6 1 1 117 대곡 하차 05-06 1
df_승하차_melted %>% tail(.)
## 월 일 역번호 역명 승하 시간 인원
## 1262165 12 31 339 지산 승차 23-24 14
## 1262166 12 31 339 지산 하차 23-24 96
## 1262167 12 31 340 범물 승차 23-24 81
## 1262168 12 31 340 범물 하차 23-24 219
## 1262169 12 31 341 용지 승차 23-24 19
## 1262170 12 31 341 용지 하차 23-24 79
가공한 데이터 2개 (df_대구메트로역
, df_승하차_melted
)를 합치자.
$역번호
를 기준으로 join 할 거다.
df_merged <- merge(x = df_승하차_melted, y = df_대구메트로역, by = "역번호", all.x = TRUE) %>%
select(., -역사명) # $역명 과 $역사명 이 중복이라서 제거.
names(df_merged)
## [1] "역번호" "월" "일" "역명" "승하" "시간" "인원"
## [8] "노선명" "역위도" "역경도"
head(df_merged)
## 역번호 월 일 역명 승하 시간 인원 노선명 역위도
## 1 115 1 1 설화명곡 승차 05-06 22 대구 도시철도 1호선 35.79872
## 2 115 1 1 설화명곡 하차 05-06 1 대구 도시철도 1호선 35.79872
## 3 115 1 1 설화명곡 하차 09-10 79 대구 도시철도 1호선 35.79872
## 4 115 1 1 설화명곡 하차 13-14 125 대구 도시철도 1호선 35.79872
## 5 115 1 1 설화명곡 하차 17-18 183 대구 도시철도 1호선 35.79872
## 6 115 1 1 설화명곡 하차 21-22 152 대구 도시철도 1호선 35.79872
## 역경도
## 1 128.4893
## 2 128.4893
## 3 128.4893
## 4 128.4893
## 5 128.4893
## 6 128.4893
tail(df_merged)
## 역번호 월 일 역명 승하 시간 인원 노선명 역위도
## 1262165 341 12 31 용지 승차 07-08 36 대구 도시철도 3호선 35.81827
## 1262166 341 12 31 용지 승차 11-12 173 대구 도시철도 3호선 35.81827
## 1262167 341 12 31 용지 승차 15-16 145 대구 도시철도 3호선 35.81827
## 1262168 341 12 31 용지 승차 19-20 66 대구 도시철도 3호선 35.81827
## 1262169 341 12 31 용지 승차 23-24 19 대구 도시철도 3호선 35.81827
## 1262170 341 12 31 용지 하차 23-24 79 대구 도시철도 3호선 35.81827
## 역경도
## 1262165 128.6465
## 1262166 128.6465
## 1262167 128.6465
## 1262168 128.6465
## 1262169 128.6465
## 1262170 128.6465
지도에 뿌리기
대구지도 가져오기 (여러 테마)
terrain
대구지도 <- get_map(c(lon = 128.60250, lat = 35.87222), zoom = 12, maptype="terrain")
ggmap(대구지도)
satellite
대구지도 <- get_map(c(lon = 128.60250, lat = 35.87222), zoom = 12, maptype="satellite")
ggmap(대구지도)
roadmap
대구지도 <- get_map(c(lon = 128.60250, lat = 35.87222), zoom = 12, maptype="roadmap")
ggmap(대구지도)
hybrid
대구지도 <- get_map(c(lon = 128.60250, lat = 35.87222), zoom = 12, maptype="hybrid")
ggmap(대구지도)
watercolor
대구지도 <- get_map(c(lon = 128.60250, lat = 35.87222), zoom = 12, maptype="watercolor")
ggmap(대구지도)
toner-2011
대구지도 <- get_map(c(lon = 128.60250, lat = 35.87222), zoom = 12, maptype="toner-2011")
ggmap(대구지도)
toner-hybrid
대구지도 <- get_map(c(lon = 128.60250, lat = 35.87222), zoom = 12, maptype="toner-hybrid")
ggmap(대구지도)
terrain-lines
대구지도 <- get_map(c(lon = 128.60250, lat = 35.87222), zoom = 12, maptype="toner-background")
ggmap(대구지도)
toner-lite
대구지도 <- get_map(c(lon = 128.60250, lat = 35.87222), zoom = 12, maptype="toner-lite")
ggmap(대구지도)
대구 지도에 지하철 역 뿌리기
- 먼저
$노선명
정리.
df_대구메트로역 <- df_대구메트로역 %>%
mutate(., 노선명 = substr(노선명,9,11))
- 전체 지하철역.
대구지도 <- get_map(c(lon = 128.60250, lat = 35.87222), zoom = 11, maptype="toner-lite")
ggmap(대구지도) + geom_point(data=df_대구메트로역, aes(역경도, 역위도, colour = 노선명))
## Warning: Removed 1 rows containing missing values (geom_point).
- zoom 이 너무 작은 값이라 판단돼서 중앙지역만 다시 그림.
대구지도 <- get_map(c(lon = 128.60250, lat = 35.87222), zoom = 12, maptype="toner-lite")
ggmap(대구지도) + geom_point(data=df_대구메트로역, aes(역경도, 역위도, colour = 노선명))
## Warning: Removed 14 rows containing missing values (geom_point).
2017년 12월 24일 오후 6시에서 7시 이용현황
- 데이터 전처리
$월
== 12 ,$일
== 25 ,$시간
== 18-19 만 가져와야함.
temp_df <- df_merged %>%
filter(., (월 == 12) & 일 == 25 & 시간 == "18-19")
- 승차인원만.
ggmap(대구지도) + geom_point(data=temp_df %>% filter(., 승하 == "승차") , aes(역경도, 역위도, colour = 노선명, size = 인원), alpha = 0.75)
## Warning: Removed 14 rows containing missing values (geom_point).
- 하차인원만.
ggmap(대구지도) + geom_point(data=temp_df %>% filter(., 승하 == "하차") , aes(역경도, 역위도, colour = 노선명, size = 인원), alpha = 0.75)
## Warning: Removed 14 rows containing missing values (geom_point).
정리, 반성 및 Future work
그림을 그리고 보니, 특히나 좀 많이 겹치는 점이 있어서 생각해보니, 환승역인 경우는 같은 역을 찾아서 이용객 수를 합쳐야 하지 않았나 싶다. (이 경우 환승역의 색도 다르게 줘야한다. 데이터 자체에 환승역에 대한 정보가 있었던 듯 하다. 다시 전처리 해보자.)
역이 너무 조밀하게 있어서 구/군별로 나눠서 표시하는 것이 나을지도 모른다는 생각이 든다. 구/군별로 그 크기가 너무 많이 다르기 때문에 그려봐야만 옳은지 그른지 판단할 수 있는 문제일지도 모른다. (구/군에 대한 공간정보를 포함한 새로운 데이터가 필요하다.)
상차인원과 하차인원을 나누면 유동인구의 움직임을 볼 수 있지 않을까 했는데 생각보다 뚜렷하게 보이지는 않는다. (12월 25일이 특수한 경우라서 그럴지도 모른다.)
shinyR을 쓰면 상호작용하는 앱을 만들수도 있겠다.
ggplotly를 쓰면 시각적으로 더 멋있는 결과를 얻을지도 모르겠다. 공부해야봐야겠다.
딱히 통계적인 요소가 들어간 것이 없는 듯 하다. 이 데이터로 사람들의 의사결정에 도움을 줄 수 있을만한 시각화를 할 수 있을까? 더 고민해봐야겠다.