공지

이번에 준비한 튜토리얼은 제 강의를 듣는 과거-현재-미래 수강생분들을 위해 준비한 자료이다. 많은 도움이 되기를 바란다

이번에 준비한 Tutorial 코로나 세계현황을 Shiny Dashboard로 만들어 가는 과정을 담았다.

I. Shiny Tutorial 소개

처음 shiny를 접하거나 shiny의 전체 튜토리얼이 궁금한 사람들을 위해 이전 글을 소개한다.

II. 코로나 바이러스 대시보드 개발 동기

강사가 처음 대시보드 강의를 기획할 때는, 이커머스 강의를 기획하고 준비했었다. 그러나, 3월부터 전세계적으로 코로나 바이러스가 확산되기 시작하면서, 코로나 바이러스 대시보드가 우후죽순처럼 생기기 시작했다.

시간이 지나더라도, 최소 10년 가까이 회자될 코로나 바이러스 대시보드를 교육용으로 만들어 둘 필요는 있다고 생각을 했다.

본 튜토리얼부터는 그동안에 익힌 R의 주요 패키지들을 활용하여 데이터 수집 - 저장 - 시각화까지 순차적으로 개발하도록 한다.

III. 코로나 바이러스!!

2019년 12월부터 중국 우한에서 급속하게 퍼진 코로나 바이러스가 전세계를 강타하기 시작했고, 2020년 4월 6일 오전 9시 기준, 전세계 확진자수는 183개국 120만명을 돌파했고, 68,000명의 사망자 숫자를 돌파했다.

이 기간 동안, (강사 포함) 많은 사람들의 경제적으로, 심리적으로, 육체적으로 어려움을 겪고 있는데, 반드시 꼭 빠른 시일안에 종식되기를 기원하며.. 데이터 분석가 본연의 업무인 시각화에 본격적으로 집중해보자.

VI. 다양한 대시보드 맛보기

3월 중순에 읽은 글 하나를 소개한다. Shiny Project에 좋은 참고자료가 될 것 같다. Top 35 R resources on Novel COVID-19 Coronavirus. 기회가 된다면 이 중에서 10개 정도는 소개하는 글을 번역하고 싶기는 하다.

V. Shiny Project - 데이터 가져오기

가장 큰 문제는 역시나 데이터 수집이다. 이번 포스트에서는 데이터 수집 후 저장까지 작성하는 코드를 보여준다.

코드에 대한 자세한 설명은 생략하며, 향후 웹 크롤링 Tutorial을 제작할 때 공유하도록 한다.

(1) 데이터 소스 확인

현재 코로나 관련 데이터의 원천은 모두 2019 Novel Coronavirus COVID-19 (2019-nCoV) Data Repository by Johns Hopkins CSSE Repository에서 관리하고 있다.

전세계에서 의료 통계에 대한 접근 권한이 일반 사용자에게는 당연히 제한된다. 즉, 주어진 데이터셋에서 다양한 대시보드를 작업해야 하는 것이 Data Scientist & Analyst에게는 기본적인 업무이다.

데이터 분석업에 처음 입문하는 분들에게는 사실 Johns Hopkins CSSE의 Repo는 굉장히 큰 배움의 장터가 될 것이다. 강사도 많이 배우고 있다. 꼭 전체적인 흐름 및 작성 요령 등을 익히기를 바란다.

여기, csse_covid_19_time_series에 있는 데이터를 가져와서 사용할 수 있지만, 본 포스트에서는 사용하지 않는다. 이유는 데이터 전처리를 조금 많이 해줘야 한다. 본인의 데이터 전처리 실력을 조금 뽐내고 싶다면, 여기에서 해도 좋다. 실제 강사가 처음 만들 때는 여기 데이터를 하기는 했다. 단순 작업들이 많은데, 시간적으로 1-2일 시간을 들여 전처리를 진행하였다.

library(RCurl)
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.0     ✓ purrr   0.3.3
## ✓ tibble  3.0.0     ✓ dplyr   0.8.5
## ✓ tidyr   1.0.0     ✓ stringr 1.4.0
## ✓ readr   1.3.1     ✓ forcats 0.4.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x tidyr::complete() masks RCurl::complete()
## x dplyr::filter()   masks stats::filter()
## x dplyr::lag()      masks stats::lag()
URL <- getURL("https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv")

data <- read.csv(text = URL, check.names = F)
print(data[1:5, 1:7])
##   Province/State Country/Region      Lat    Long 1/22/20 1/23/20 1/24/20
## 1                   Afghanistan  33.0000 65.0000       0       0       0
## 2                       Albania  41.1533 20.1683       0       0       0
## 3                       Algeria  28.0339  1.6596       0       0       0
## 4                       Andorra  42.5063  1.5218       0       0       0
## 5                        Angola -11.2027 17.8739       0       0       0

위 데이터는 확진자와 사망자 모두를 포함하고 있지 않다. 다시 말하면, 위 데이터 모두를 가져와서 날짜별로 재정리하는 코드가 남았다. (무언가 복잡한 것 같다!! 실제로 그렇다!!) 데이터 전처리는 숙제로 과제로 남겨두겠다. 강사가 정리한 것이 있기는 하다! 그러나, 여기에서 보여주지는 않을 것이다!! (프로젝트 마지막날에 공유해주겠다!)

그래서 수강생들이 조금 더 정제된 데이터를 웹에서 불러와서 사용할 만한 것을 찾았다!! Hooray!! Euro Open Data Portal

이제 여기에서 데이터를 수집할 것이다! 다행히 Access URL이 있다. (강사는 백업으로 강사 데이터 github 저장소에 별도로 보관했다. ) - 1차 백업: 2020-04-06

(2) 데이터 수집

이제 본격적으로 데이터 수집 및 간단한 데이터 처리를 진행한다.

library(readxl)
library(httr)

# URL Copy
url <- 'https://www.ecdc.europa.eu/sites/default/files/documents/COVID-19-geographic-disbtribution-worldwide.xlsx'

# 파일 이름만 가져오기
getFileName <- basename(url)

# 지정된 디렉토리에 파일 다운로드 받기
download.file(url = url, destfile = getFileName)
# 현재 객체의 파일 리스트 확인
list.files()
## [1] "COVID-19-geographic-disbtribution-worldwide.xlsx"
## [2] "getData.R"                                       
## [3] "project_01.html"                                 
## [4] "project_01.md"                                   
## [5] "project_01.Rmd"
# 지정된 디렉토리에서 파일 업로드 하기
data <- read_excel(getFileName)
head(data)
## # A tibble: 6 x 10
##   dateRep               day month  year cases deaths countriesAndTer… geoId
##   <dttm>              <dbl> <dbl> <dbl> <dbl>  <dbl> <chr>            <chr>
## 1 2020-04-05 00:00:00     5     4  2020    35      1 Afghanistan      AF   
## 2 2020-04-04 00:00:00     4     4  2020     0      0 Afghanistan      AF   
## 3 2020-04-03 00:00:00     3     4  2020    43      0 Afghanistan      AF   
## 4 2020-04-02 00:00:00     2     4  2020    26      0 Afghanistan      AF   
## 5 2020-04-01 00:00:00     1     4  2020    25      0 Afghanistan      AF   
## 6 2020-03-31 00:00:00    31     3  2020    27      0 Afghanistan      AF   
## # … with 2 more variables: countryterritoryCode <chr>, popData2018 <dbl>

국가별로 깔끔하게 정리된 데이터를 확인할 수 있다.

VI. Shiny Project - 데이터 전처리

간단하게 데이터를 전처리를 해보자. 데이터를 수집한 뒤에 무조건 전처리를 해줘야 한다! (데이터 전처리 함수를 별도로 만드는 과정을 진행해야 한다!)

혹시, R이 저용량에서만 사용하는 것 아니냐는 우문이 나올 것 같아서 링크 하나를 남겨둔다! 꼭 참고하기를 바란다 (입문자에게는 어려울 수 있다!).

데이터 전처리를 할 작업은 한가지만 진행한다. - dplyr 패키지의 select()함수를 활용하여 day, month, year, geoId을 삭제한다.

data2mongo <- data %>% select(-c(day, month, year, geoId))
head(data2mongo)
## # A tibble: 6 x 6
##   dateRep             cases deaths countriesAndTer… countryterritor… popData2018
##   <dttm>              <dbl>  <dbl> <chr>            <chr>                  <dbl>
## 1 2020-04-05 00:00:00    35      1 Afghanistan      AFG                 37172386
## 2 2020-04-04 00:00:00     0      0 Afghanistan      AFG                 37172386
## 3 2020-04-03 00:00:00    43      0 Afghanistan      AFG                 37172386
## 4 2020-04-02 00:00:00    26      0 Afghanistan      AFG                 37172386
## 5 2020-04-01 00:00:00    25      0 Afghanistan      AFG                 37172386
## 6 2020-03-31 00:00:00    27      0 Afghanistan      AFG                 37172386

VII. MongoDB에 저장

데이터를 올린 것은 좋았지만, 아직 끝난 것은 아니다. 현재 사용중인 Session을 종료하면 (또는 RStudio)를 종료하면 전처리된 데이터는 당연히 사라진다.

즉, 다시 전처리 코드를 실행해야 한다. (했던 것을 또하기는 싫다.) 이렇게 저장된 데이터를 Database에 저장해야 하는데, 기존에 학습했던 MongoDB에 저장한다. 여기서 저장된 데이터를 Shiny Server에서 불러와서 대시보드로 작업하는 코드를 구현할 것이다!

library(mongolite)
collection <- "covid_19" 
db <- 'learningspoons'
mongo_id <- Sys.getenv("MONGO_ID") # 보안 유지를 위해 가렸다.(실무에서는 이렇게 작업하라고 권유하는 것임!) 
mongo_pw <- Sys.getenv("MONGO_PW") # (실무에서는 이렇게 작업하라고 권유하는 것임!)  

mongo_url <- paste0('mongodb+srv://', mongo_id, ':',mongo_pw,'@learningspoons-rhpei.gcp.mongodb.net/')

conn <- mongo(collection = collection, 
              db = db, 
              url = mongo_url)

print(conn)
## <Mongo collection> 'covid_19' 
##  $aggregate(pipeline = "{}", options = "{\"allowDiskUse\":true}", handler = NULL, pagesize = 1000, iterate = FALSE) 
##  $count(query = "{}") 
##  $disconnect(gc = TRUE) 
##  $distinct(key, query = "{}") 
##  $drop() 
##  $export(con = stdout(), bson = FALSE, query = "{}", fields = "{}", sort = "{\"_id\":1}") 
##  $find(query = "{}", fields = "{\"_id\":0}", sort = "{}", skip = 0, limit = 0, handler = NULL, pagesize = 1000) 
##  $import(con, bson = FALSE) 
##  $index(add = NULL, remove = NULL) 
##  $info() 
##  $insert(data, pagesize = 1000, stop_on_error = TRUE, ...) 
##  $iterate(query = "{}", fields = "{\"_id\":0}", sort = "{}", skip = 0, limit = 0) 
##  $mapreduce(map, reduce, query = "{}", sort = "{}", limit = 0, out = NULL, scope = NULL) 
##  $remove(query, just_one = FALSE) 
##  $rename(name, db = NULL) 
##  $replace(query, update = "{}", upsert = FALSE) 
##  $run(command = "{\"ping\": 1}", simplify = TRUE) 
##  $update(query, update = "{\"$set\":{}}", filters = NULL, upsert = FALSE, multiple = FALSE)
conn$count('{}')
## [1] 8905
conn$insert(data2mongo)
## List of 5
##  $ nInserted  : num 8905
##  $ nMatched   : num 0
##  $ nRemoved   : num 0
##  $ nUpserted  : num 0
##  $ writeErrors: list()
conn$count('{}')
## [1] 17810

데이터가 들어간 숫자만큼 나와면 정상이다. 이렇게 전처리에 들어간 데이터를 보통 실무에서는 Data Mart 분석 테이블

이렇게 간단하게 코로나 데이터 수집부터 몽고DB에 저장하는 것 까지 실습 했다.

다음 장에서는 Leaflet + Shiny Source 코드를 직접 구현하도록 한다.

Congratulation! You Mastered Application of CSS in Shiny