작업흐름1

공공데이터포털 웹사이트에서 API KEY를 발급받아 “동네예보 조회서비스”에서 날씨 정보를 가져온다. 문제는 매번 시간이 지나는데 이를 계속해서 로컬 컴퓨터에서 컴파일하는 것은 사람이 할 일이 아니다. 이를 자동화하기 위해서 정확히는 돈(?)과 노력(?)을 들이지 않는 방법을 찾아보자. 이를 위해서 GitHub Actions를 염두에 두고 .Rmd 파일에 “날씨 정보를 가져와서 보고서를 HTML 파일”로 제작하는 것을 cron 작업으로 연계해보자.

1 날씨관련 지도정보

먼저 기상청 날씨데이터 서비스 - 기상자료개발포털 웹사이트에서 데이터만 제공하고 있으며 관련된 RESTful API를 사용하기 위한 API KEY는 공공데이터포털 - 동네예보 조회서비스에서 받아 저장한다.

1.1 시군구 읍면동

동네예보 조회서비스 오픈 API 활용가이드를 참고하면 동네를 특정하기 위한 공간지리 정보가 읍면동 단위로 상세히 제공되고 있다.

library(sf)
library(tidyverse)
library(readxl)
library(leaflet)
library(glue)

map_df <- read_excel("data/기상청18_동네예보 조회서비스_오픈API활용가이드_격자_위경도(20200706).xlsx", sheet = "최종업데이트파일_20200706")

map_df <- map_df %>% 
  mutate(long = as.numeric(`경도(초/100)`),
         lat  = as.numeric(`위도(초/100)`))

map_df %>% 
  filter(`2단계` == "성남시분당구") %>% 
    leaflet() %>% 
    addProviderTiles(provider = providers$OpenStreetMap) %>% 
    addMarkers(lng=~long, lat = ~lat, clusterOptions = markerClusterOptions(),
               popup = ~ as.character(glue("<strong> {`행정구역코드`} </strong> <br>
                                           &middot; 시도명: {`1단계`} <br>
                                           &middot; 시군구명: {`2단계`} <br>
                                           &middot; 읍면동: {`3단계`}")))

2 API KEY 테스트

발급받은 API KEY를 R에서 불러와서 활용할 수 있도록 glue 팩키지와 usethis::edit_r_environ() 함수를 사용해서 API KEY정보를 저장시키고 Sys.getenv("KMA_KEY") 명령어로 불러와서 RESTful API 조회를 준비한다.

library(tidyverse)
library(glue)

KMA_KEY <- Sys.getenv("KMA_KEY")

kma_url <- glue("http://apis.data.go.kr/1360000/VilageFcstInfoService/getVilageFcst?serviceKey={KMA_KEY}&numOfRows=10&pageNo=1&base_date=20201021&base_time=0230&nx=55&ny=127&dataType=JSON")

앞서 작성한 RESTful API 요청을 curl명령어로 던져 결과를 확인한다.

curl --include --request GET 'http://apis.data.go.kr/1360000/VilageFcstInfoService/getVilageFcst?serviceKey=XKpB4XVSokub2d4g0ADRVllCwUM%2BwmT5k5PhBLUCXb2hcW0LgHm%2BRHs2O%2BdWi4S0JJQECMZEVEx0VV1ZuJDDUw%3D%3D&numOfRows=10&pageNo=1&base_date=20200912&base_time=0230&nx=55&ny=127&dataType=JSON'
읠挼㸸戼㸴 

2.1 성남시분당구 날씨

성남시 분당구 격자정보(X, Y)를 파악한다.

map_df %>% 
  filter(`2단계` == "성남시분당구") %>% 
  count(`격자 X`, `격자 Y`)
# A tibble: 4 x 3
  `격자 X` `격자 Y`     n
  <chr>    <chr>    <int>
1 62       122          9
2 62       123         10
3 63       122          1
4 63       123          3

기상청18_동네예보 조회서비스_오픈API활용가이드.docx 문서에서 코드값 정보를 참조하여 동네예보 항목값(category)에 대한 정보를 사전에 코드화시켜 데이터프레임으로 준비한다.

code_table <- tribble(~"category", ~"항목명", ~"단위", 
                      "POP", "강수확률", "%",
                      "PTY", "강수형태", "코드값",
                      "R06", "6시간 강수량", "범주 (1 mm)",
                      "REH", "습도", "%",
                      "S06", "6시간 신적설", "범주(1 cm)",
                      "SKY", "하늘상태", "코드값",
                      "T3H", "3시간 기온", "℃",
                      "TMN", "아침 최저기온", "℃",
                      "TMX", "낮 최고기온", "℃",
                      "UUU", "풍속(동서성분)", "m/s",
                      "VVV", "풍속(남북성분)", "m/s",
                      "WAV", "파고", "M",
                      "VEC", "풍향", "m/s",
                      "WSD", "풍속", "1")

격자정보 nx=62, nx=63, ny=122, ny=123 조합하면 총 4개 지역이 나오지만 먼저 nx=62, ny=122 을 조합한 성남시 분당구 한 구역만 예측 날씨값을 가져온다.

  • 하늘상태(SKY) 코드 : 맑음(1), 구름많음(3), 흐림(4)
  • 강수형태(PTY) 코드 : 없음(0), 비(1), 비/눈(2), 눈(3), 소나기(4), 빗방울(5), 빗방울/눈날림(6), 눈날림(7)
library(rvest)
library(httr)

## 날짜 전처리
today_date <- Sys.Date() %>%  as.character() %>% 
  str_remove_all(pattern = "-")

## RESTful 호출
bundang_kma_url <- glue("http://apis.data.go.kr/1360000/VilageFcstInfoService/getVilageFcst?serviceKey={KMA_KEY}&numOfRows=10&pageNo=1&base_date={today_date}&base_time=0230&nx=62&ny=122&dataType=JSON")

bundang_resp <- GET(bundang_kma_url)

## JSON --> 데이터프레임 변환
bundang_list <- jsonlite::fromJSON(content(bundang_resp, "text"), simplifyVector = FALSE)

bundang_df <- data.frame(Reduce(rbind, bundang_list$response$body$items$item)) %>% 
  as_tibble() %>% 
  mutate_all(unlist)

## 데이터프레임 가독성 있게 표현
bundang_df <- bundang_df %>% 
  left_join(code_table, by="category") %>% 
  select(fcstDate, fcstTime, category, 항목명, fcstValue, 단위)

bundang_df
# A tibble: 10 x 6
   fcstDate fcstTime category 항목명         fcstValue 단위       
   <chr>    <chr>    <chr>    <chr>          <chr>     <chr>      
 1 20200913 0600     POP      강수확률       20        %          
 2 20200913 0600     PTY      강수형태       0         코드값     
 3 20200913 0600     R06      6시간 강수량   0         범주 (1 mm)
 4 20200913 0600     REH      습도           80        %          
 5 20200913 0600     S06      6시간 신적설   0         범주(1 cm) 
 6 20200913 0600     SKY      하늘상태       3         코드값     
 7 20200913 0600     T3H      3시간 기온     17        ℃          
 8 20200913 0600     TMN      아침 최저기온  17.0      ℃          
 9 20200913 0600     UUU      풍속(동서성분) 0         m/s        
10 20200913 0600     VEC      풍향           360       m/s        

2.2 시각화

JSON 날씨정보를 데이터프레임으로 변환시켰다면 다음 단계로 데이터 과학의 강력한 기능을 시각화를 통해 진정한 힘을 보여준다.

plot_title <- glue::glue("성남시 분당구 동네예보 서비스: {unique(bundang_df$fcstDate)}, {unique(bundang_df$fcstTime)}")
                         
bundang_df %>% 
  mutate(fcstValue = as.numeric(fcstValue)) %>% 
  filter(항목명 %in% c("강수확률", "습도")) %>% 
  ggplot(aes(x=항목명, y=fcstValue, fill = 항목명)) +
    geom_col(width=0.5, show.legend = FALSE) +
    facet_wrap(~항목명, scales="free_x")  +
    labs(x="", y="확률(%)", title=plot_title)+
    theme_bw()

3 Rmd 스크립트 작성 [1]

상기 코드가 포함된 보고서를 Rmd 스크립트로 작성한다. 문제는 API KEY가 노출된다는 점인데 이는 GitHub Action에서 다른 방식으로 보완하기로하고 우선은 제대로 동작이 되는지만 확인한다.

xfun::embed_file('rpa-write-rmd-file.Rmd')
Download rpa-write-rmd-file.Rmd

3.1 Rmd 스크립트 컴파일

날씨예보 보고서를 쉘환경에서 컴파일하기 때문에 먼저 rmarkdown::render() 함수로 테스트를 한다.

  • Rscript -e rmarkdown::render("rpa-write-rmd-file.Rmd")
rmarkdown::render("rpa-write-rmd-file.Rmd")

  |                                                                            
  |                                                                      |   0%
  |                                                                            
  |..........                                                            |  14%
  ordinary text without R code


  |                                                                            
  |....................                                                  |  29%
label: unnamed-chunk-2 (with options) 
List of 1
 $ include: logi FALSE


  |                                                                            
  |..............................                                        |  43%
  ordinary text without R code


  |                                                                            
  |........................................                              |  57%
label: code-table-for-rmd

  |                                                                            
  |..................................................                    |  71%
  ordinary text without R code


  |                                                                            
  |............................................................          |  86%
label: weather-data-viz-for-rmd

  |                                                                            
  |......................................................................| 100%
  ordinary text without R code


"C:/PROGRA~3/CHOCOL~1/bin/pandoc" +RTS -K512m -RTS rpa-write-rmd-file.utf8.md --to html4 --from markdown+autolink_bare_uris+tex_math_single_backslash --output rpa-write-rmd-file.html --email-obfuscation none --self-contained --standalone --section-divs --table-of-contents --toc-depth 3 --variable toc_float=1 --variable toc_selectors=h1,h2,h3 --variable toc_collapsed=1 --variable toc_smooth_scroll=1 --variable toc_print=1 --template "C:\Users\statkclee\Documents\R\win-library\4.0\rmarkdown\rmd\h\default.html" --highlight-style tango --number-sections --variable "theme:bootstrap" --include-in-header "C:\Users\STATKC~1\AppData\Local\Temp\RtmpKcVnKY\rmarkdown-str44b4223813d7.html" --mathjax --variable "mathjax-url:https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" --lua-filter "C:/Users/statkclee/Documents/R/win-library/4.0/rmarkdown/rmd/lua/pagebreak.lua" --lua-filter "C:/Users/statkclee/Documents/R/win-library/4.0/rmarkdown/rmd/lua/latex-div.lua" --variable code_folding=hide --variable code_menu=1 --include-in-header header.html --include-after-body footer.html 

1. Kaupp J. Using r to collect, analyze and visualize graduate attribute data. Proceedings of the Canadian Engineering Education Association (CEEA). 2016.

 

데이터 과학자 이광춘 저작

kwangchun.lee.7@gmail.com