서울시 구별 생활체육시설에 분석 및 지도로 나타내기

목표

  1. 서울시의 자치구를 지도로 나타냄

  2. 자치구에 생활체육시설 종류별로 지도에 색깔로 표현

  3. 각 자치구의 생활체육시설의 변화를 시계열로 나타냄.

  4. shiny를 사용하여 각 자치구의 생활체육시설을 종류별로 지도에 크기로 표현

자료 수집

  1. 서울시 생활체육시설 현황 자료

    http://data.seoul.go.kr/dataList/1391/S/2/datasetView.do#none에서 2010~2019년 자료를 다운로드 한 후,

    위의 3행을 삭제하고, 숫자 컬럼의 ’,’를 모두 제거한 후 csv로 저장

  2. GIS 한국 행정명에 따른 지도

    http://www.gisdeveloper.co.kr/?p=2332 에서 ‘시군구’, ‘2021년 1월 업데이트 다운로드’

Import Library

library(tidyverse) # dplyr, ggplot2 모두 포함
library(sf) # GIS 데이터 처리

서울시 생활체육시설 현황 자료 전처리

자료 읽어오기

df = read_csv("data/data.csv", locale=locale('ko',encoding='euc-kr'))

컬럼의 이름을 모두 영문으로 변경: 애매한 것들은 구글번역기에서 한글의 로마자 표기 이용.

names(df)<-c('year', 'gu', 'tot_cnt', 'tot_area', 'yoteujang_cnt','yoteujang_area','ice_link_cnt','ice_link_area','jonghabcheyugsiseol_cnt', 'jonghabcheyugsiseol_area','swimming_pool_cnt','swimming_pool_area', 'cheyugdojang_cnt','cheyugdojang_area','golpeuyeonseubjang_cnt','golpeuyeonseubjang_area','fitness_cnt','fitness_area','billiard_cnt','billiard_area','sseolmaejang_cnt','sseolmaejang_area','mudojang_cnt','mudojang_area','mudohag-won_cnt','mudohag-won_area','golpeujang_cnt','golpeujang_area')

컬럼 전처리

df[,3:28]<-df[,3:28] %>% sapply(as.integer) #har로 되어 있는 숫자 컬럼을 모두 숫자로(integer)로 변경
df$year <- as.character(df$year) # year 컬럼을 char로 변경
df <- df %>% filter(gu!='서울시') # 'gu'컬럼에 '서울시'는 모두 제거
df[is.na(df)]<-0 # na 값은 모두 0 값이므로 0으로 채움

서울시 지도 처리

shapefile 읽어오기

서울시의 각 구별 지도를 불러오기 위해서는 ‘시군구’ 지도를 불러와야 한다.

GIS의 Shapefile을 읽어오는 방법이 sf 객체를 읽어오는 방법이 있고, sp 객체로 읽어오는 방법이 있는데,

sf 객체는 data frame의 형태로 읽어오고, sp는 S4 클라스로 읽어오는데, geom_sf를 사용하여 지도를 그리기에 편하므로 여기서는 sf 객체로 읽어와서 처리하겠다.

sig<-st_read('data', 'TL_SCCO_SIG')
Reading layer `TL_SCCO_SIG' from data source `C:\Rproject\seoul\data' using driver `ESRI Shapefile'
Simple feature collection with 250 features and 3 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: 746110.3 ymin: 1458754 xmax: 1387948 ymax: 2068444
projected CRS:  PCS_ITRF2000_TM
sig$SIG_KOR_NM <- iconv(sig$SIG_KOR_NM, localeToCharset(), 'UTF-8') # 한글 처리 

서울시 지도만 추출하기

sig %>% filter(str_detect(SIG_KOR_NM, '구로구')) # 서울시의 'SIG_CD'를 알아내기 위해서
Simple feature collection with 1 feature and 3 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: 939273.8 ymin: 1941770 xmax: 947237.9 ymax: 1946679
projected CRS:  PCS_ITRF2000_TM
  SIG_CD SIG_ENG_NM SIG_KOR_NM                       geometry
1  11530    Guro-gu     구로구 MULTIPOLYGON (((945165.3 19...
seoul_sig <- sig %>% 
  filter(str_detect(SIG_CD, '11[0-9]{3}'))

서울시 지도 그려보기

seoul_sig %>% 
  ggplot()+
  geom_sf(aes(fill=SIG_KOR_NM))+
  geom_sf_text(aes(label=SIG_KOR_NM))+
  theme(legend.position = 'none')

생활체육시설 분석 및 지도로 구현

생활체육시설 데이터(df)와 지도(seoul_sig) 데이터 병합

df_map <- 
  left_join(x = seoul_sig, y = df, by=c('SIG_KOR_NM'='gu'))

병합된 데이터 생활체육시설을 각 구별로 지도로 구현

여기서는 2019년, 그리고 tot_cnt를 그렸다.

년도와 알고 싶은 생활체육시설을 바꿔가면서 그려볼 수 있다.

df_map %>% 
  filter(year=='2019') %>% 
  ggplot()+
  geom_sf(aes(fill=SIG_KOR_NM))+
  geom_sf_text(aes(label = paste0(SIG_KOR_NM,"\n","(",as.integer(tot_cnt),")")), size=3)+
  theme(legend.position = 'none')+
  labs(title = "서울시 각 구별 생활체육시설 총 개수")+
  theme(plot.title = element_text(hjust = 0.5))

시계열 데이터(2010~2019) 그래프

시계열 데이터는 지도를 그릴 필요가 없기 때문에 df데이터만 있으면 됨.

library(ggrepel) # For geom_text_repel instead of geom_text

df %>% 
  ggplot(aes(x = year, y = tot_cnt))+
  geom_line(aes(color=gu, group=gu))+
  geom_point(aes(color=gu))+
  scale_y_log10(n.breaks=10)+
  #scale_y_sqrt(n.breaks=10)+
  labs(title = "서울시 각 구별 생활체육시설 총계(log 스케일임을 주의)")+
  theme(plot.title = element_text(hjust = 0.5),legend.position = 'none')+
  geom_text_repel(data=df %>% filter(year=='2010'),aes(label=gu, color=gu), size=2.5, hjust=1.2, vjust=0.1)

대화형 그래프

대화형으로 생활체육시설을 선택해서 그려보기 위해서 아래와 같이 shiny로 구현을 해 보았다.

그런데, 아쉽게도 여기 ‘rpub’ 사이트는 정적인 html만 지원하기 때문에 shiny 앱이 동작을 하지 않는다.

그래서 코드만 아래와 같이 적어 놓았다. 실제 Rstudio에서는 아래 그림과 같이 동작한다.

아래는 해당 코드이다

# library(shiny)
# 
# shinyApp(
#   ui = fluidPage(
#     varSelectInput("variable", "Variable:", df[,3:28]), #데이터 프레임의 열 이름으로 선택 목록을 만듬. id, label, data. server의 !!input$variable
#     plotOutput("data") # server의 output$data와 협력(co-work)
#   ),
#   server = function(input, output) {
#     output$data <- renderPlot({
#       ggplot(df, aes(x = year, y = !!input$variable))+ #y = tot_cnt -> y = !!input$variable
#         geom_line(aes(color=gu, group=gu))+
#         geom_point(aes(color=gu))+
#         #scale_y_log10(n.breaks=10)+
#         #scale_y_sqrt(n.breaks=10)+
#         theme(legend.position = 'none')+
#         geom_text_repel(data=df %>% filter(year=='2010'),
#                         aes(label=gu, color=gu),
#                         size=2.5, hjust=2.0, vjust=0.1)
#     })
#   }
# 
# )