태그 보관물: R

R로 스타벅스 지역별 매장수 분석, 데이터 크롤, 데이터 분석

R언어로 , 스타벅스 매장 데이터를 크롤해서 분석하는 간단한 예제 스크립트입니다.

전체 코드는 글 아래 쪽에 있습니다.

코드 설명

예제에서 하려는 것

간단하게 재미 삼아하는 토이(toy) 분석입니다. 실제 분석 프로젝트에서는 이 보다는 더 심도가 깊게 해야 합니다.

이 분석의 실제 목적은 R로 데이터 크롤을 해서 분석은 어떻게 하는 것인지 설명하는 것입니다. 분석 리포트에서는 크롤한 데이터를 이용해서 인사이트를 도출하고 탐색적데이터분석(EDA)를 어떻게 하는지 예제로 보여줍니다.

이 분석에서 해보려고 하는 것은 스타벅스의 매장 목록을 가져와서 각 시도별, 구군별로 어느 지역에 스타벅스 매장이 가장 많은지 어떤 인사이트가 있는지 살펴보고 또 지역별 인구수와 스타벅스 매장 수와 관계가 있는지를 확인해 보는 간단한 분석입니다.

분석에 들어가기 전에 상식적으로 식음료 판매 매장들은 유동인구가 많은 곳에 자리를 잡는 것이 일반적이기 때문에 당연히 지역별 인구수와 스타벅스 매장 수는 관련이 있을 것이라고 추측할 수 있습니다.

그래서 서울이라면 강남 지역에 스타벅스가 가장 많을 것이라고 추측해 볼 수 있습니다. 서울은 강남에 오피스가 가장 많아서 직장이들도 많고 유동 인구도 많습니다. 정말 그런지 확인은 해봐야 겠지요.

그래서 여기서 확인해 볼 가설은 “스타벅스 매장의 위치는 지역의 인구수 또는 유동인구와 관련이 있을 것이다.” 라는 것입니다.

너무 뻔한 것이어서 굳이 세심하게 분석할 필요가 없다고 생각할지 모르지만 하지만 이미 알고 있거나 너무 뻔한 사실도 실제로 그런지 확인하는 것도 유의미합니다.

의외성이 많아지는 요즘 세상은 알고 있던 상식이 실제와는 다른 경우도 많기 때문입니다.

먼저 알아야 할 것

이 포스트에서 하려는 것을 할 때 꼭 알아야 할 정보와 필요한 것은 3가지입니다.

  • 매장의 위치 데이터 제공처
  • 매장의 위치데이터 데이터를 크롤(스크랩)하는 법
  • 크롤한 데이터를 잘 정제, 정돈하는 법

R언어 사용법 등은 당연히 알아야 하는 것이라 목록에는 안 적었습니다.

Python이나 다른 언어로 해도 되지만 여기서는 R언어로 하겠습니다.

데이터를 얻어 오는 곳

이런 정보가 어디 있는지는 검색을 해서 알아내야 합니다. 검색해보니 대충 아래와 같은 것이 제일 만만해 보입니다.

먼저 스타벅스 매장 주소 데이터는 스타벅스 웹사이트에서 가져오면 되는데 csv나 엑셀 파일로 다운로드하게 지원하지 않으니 웹페이지의 내용물을 읽어서 파싱(parsing)해야 합니다.

이 작업은 웹 스크랩이라고 하는데 흔히 크롤이라고 부릅니다. 사실 원래 크롤과 스크랩은 서로 차이가 많습니다만 이 글에서는 그냥 널리 알려진 대로 크롤이라고 하겠습니다.

또 스타벅스 웹페이지는 지도상에 매장의 위치를 표시하기 위해서 Ajax로 데이터를 호출하는 방식을 사용하는데 이것의 방식을 알아내서 어떻게 데이터를 가져와야 하는지도 알고 있어야 합니다.

보통 크롬이나 파이어폭스의 개발자도구를 사용해서 알아내는데 연습과 방법을 익히는데 시간과 노력이 필요합니다. IT활용능력, 웹개발능력과 관련이 있는 것이라서 이것까지 설명하려면 설명이 길어지므로 이것을 알아내는 방법은 여기서는 생략합니다. 다음 기회에 다른 포스트에서 하겠습니다.

이 글에 소스코드를 넣어 두었으니 이미 완성된 코드를 참고 참고하세요.

인구데이터는 국가통계포털 웹사이트에서 가져오면 됩니다. csv나 excel로 다운로드 할 수 있게 지원하므로 매우 편합니다만 그래도 역시 데이터 정제, 정돈 작업은 좀 필요합니다.

인구데이터는 여기 말고도 받을 수 있는 곳이 더 있습니다. 더 편한곳이 있으면 그냥 거기를 이용하세요.

데이터를 크롤하는 법

R언어는 텍스트 파일을 파싱하거나 json 데이터를 처리하는 것이 조금 복잡한 편에 속합니다. R언어가 수치와 벡터 계산에 중점을 두기 때문에 이런 텍스트 처리에는 매우 약합니다.

하기가 까다롭다는 말입니다.

이런 것을 하려면 Python이나 Javascript가 더 나은 선택이지만

R언어로 이걸 하면 한 코드에서 데이터 크롤, 정제, 분석, 시각화까지 한 번에 할 수 있어 관리가 편하고 나중에 코드를 다시 볼 때 전체 흐름을 이해하기 편하다는 장점이 있습니다.

어쨌든 R언어에서 httr, urltools, jsonlite 패키지의 사용법을 익히면 됩니다.

데이터 정제, 정돈

데이터랭글링이라는 것을 할 텐데 이런 작업은 tidyverse 패키지에 포함된 여러 패키지를 이용하는 것이 가장 세련되고 좋은 방법입니다.

그리고 시각화는 ggplot2를 사용하겠습니다.

결과

스타벅스 전체 매장수: 1658개

1658개로 나옵니다. 스타벅스는 모두 신세계에서 운영하는 직영점이라고 알려져 있고 관리가 웹사이트 관리가 잘 되고 있을 것이라고 생각돼서 이 수치는 맞을 것입니다.

수천개는 될 것 같지만 제 예상보다는 적습니다.

시도별 매장수

   sido               n
   <chr>          <int>
 1 서울특별시       571
 2 경기도           383
 3 부산광역시       128
 4 대구광역시        71
 5 인천광역시        67
 6 경상남도          66
 7 광주광역시        59
 8 대전광역시        59
 9 경상북도          48
10 충청남도          36
11 울산광역시        29
12 전라북도          29
13 강원도            28
14 충청북도          26
15 전라남도          25
16 제주특별자치도    22
17 세종특별자치시    11

시도별 매장수는 역시 서울이 가장 많고 그 다음은 경기도, 부산 순입니다. 인구수가 많은 시도에 매장이 더 많은 것을 알 수 있습니다.

네 당연하죠. 물론 지역별로 로컬 카페나 다른 프렌차이즈, 브랜드의 커피매장이 더 인기가 있는 지역이 있을 수도 있으니 이 가설이 틀렸을 여지는 있습니다.

차트로 보며 시도별 매장수의 규모를 더 직관적으로 확인할 수 있는데 서울특별시와 경기도를 합치면 다른 시도를 다 합친 것 보다 더 많습니다.

우리나라 스타벅스 매장은 수도권에 크게 집중되어 있습니다.

구군별 매장수

   sido       gugun        n sido_gugun           
   <chr>      <chr>    <int> <chr>                
 1 서울특별시 강남구      88 서울특별시   강남구  
 2 서울특별시 중구        52 서울특별시   중구    
 3 서울특별시 서초구      48 서울특별시   서초구  
 4 경기도     성남시      47 경기도   성남시      
 5 경기도     고양시      42 경기도   고양시      
 6 서울특별시 영등포구    40 서울특별시   영등포구
 7 서울특별시 종로구      39 서울특별시   종로구  
 8 경기도     수원시      35 경기도   수원시      
 9 경기도     용인시      34 경기도   용인시      
10 서울특별시 송파구      34 서울특별시   송파구  

구군별로 매장수를 살펴보면 역시 서울 강남구가 가장 많습니다. 한국에서 아마 인구밀도가 가장 높은 지역이며 유동인구와 일과시간에 직장인이 가장 많이 있는 곳입니다.

그 다음은 역시 유동인구가 가장 많고 오피스밀집 지역이며 인구밀도가 높은 서울 중구입니다. 중구에는 명동, 충무로, 을지로가 있습니다.

그 다음은 서울 서초구인데 서초구는 강남구와 인구밀도는 비슷하지만 오피스공간 보다는 주거지역이 훨씬 많기 때문에 강남구나 중구에 비해서 낮시간에 직장인이 아주 많지는 않습니다. 그래도 괘나 많습니다.

그리고 그 다음은 경기도 성남시인데 성남에는 분당과 판교가 있으며 성남전체의 인구도 많으므로 이것도 당연합니다.

서울-강남구에 스타벅스가 압도적으로 많으며 다른 대형 지역구들도 제법 많습니다. 앞서 말했듯이 이 지역은 직장인들이 주중에 많이 머무는 지역들입니다. 물론 여기 나온 인구수는 거주 인구수이기 때문에 직장인이 주중에 많다는 것과의 상관관계를 다시 확인해야 할 필요가 있습니다만 알려진 바로는 매우 특별한 경우를 빼면 거주인구가 많은 지역에 직장도 많습니다.

인구수와 매장수의 상관관계

	Pearson's product-moment correlation
data:  sido_tbl$n and sido_tbl$total
t = 7.6707, df = 15, p-value = 1.439e-06
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.7216524 0.9609928
sample estimates:
      cor 
0.8926678 

시도별 인구수와 스타벅스 매장수의 상관관계를 보면 상관계수가 0.89로 강한 상관이며 검정에서 대립가설 채택으로 상관이 있다는 결과가 나옵니다.

더 해볼 것

상관관계를 볼 때 단순 인구수가 아닌 면적을 인구수로 나눠서 인구밀집도를 구한 다음에 상관관계를 보는 것이 더 합리적이겠지만 면적데이터를 가져와서 붙여야 하니 귀찮아서 생략하겠습니다.

또 구군별로도 면적데이터를 가져와서 구군별로도 인구수와 스타벅스 매장수가 상관이 있는지 확인해 보는 것도 필요합니다만 이것도 생략하겠습니다.

혹시 해보고 싶으시면 아래 소스를 보시고 고쳐서 직접 한 번 해보세요.

결론 및 인사이트

매장수와 지역의 인구밀집도는 관계가 있습니다.

시도별, 구군별로 모두 상관관계가 있습니다.

따라서 스타벅스매장이 많은 곳은 인구밀집도가 높은 지역일 가능성이 큽니다.

인구밀집도는 유동인구수와 상관관계가 있는 것으로 알려져 있습니다.

스타벅스 매장이 많은 곳(있는 곳)은 유동인구가 많은 곳입니다.

마약 누군가 많은 유동인구가 필요한 점포를 개업하려고 한다면 스타벅스 부근에 개점하면 됩니다.

길거리 음식을 팔거나 판매하려면 패션 팟업스토어, 푸드 트럭을 열려면 스타벅스 근처에 하면 잘 될 것입니다. 물론 그게 가능하다면 말이죠.

전체 스크립트

소스 파일

https://github.com/euriion/r-exams/blob/main/starbucks_analysis.R

소스 내용

# 스타벅스 목록을 읽어서 간단한 통곗값을 출력하는 R 스크립트
# install.packages(c("httr", "urltools", "jsonlite"))
library(httr)
library(urltools)
library(jsonlite)
# 데이터를 긁어올 사이트: https://www.starbucks.co.kr
# 시도 목록을 가져오는 부분
url <- "https://www.starbucks.co.kr/store/getSidoList.do"
res_content <- POST(url)
res_object <- fromJSON(content(res_content, "text"))
sido_items <- tibble(sido_nm=res_object$list$sido_nm, sido_cd=res_object$list$sido_cd)
# 구군 목록을 가져오는 코드. 구군은 분석에 필요하지 않으므로 리마킹
# url = "https://www.starbucks.co.kr/store/getGugunList.do"
# post_params = "sido_cd=01&rndCod=4X93H0I94L"
# res_content <- POST(url, body=parse_url(sprintf("%s?%s", url, post_params))$query)
# res_object <- fromJSON(content(res_content, "text"))
# 각 시도별 주소를 가져오는 부분
url <- "https://www.starbucks.co.kr/store/getStore.do"
payload <- "in_biz_cds=0&in_scodes=0&search_text=&p_sido_cd=08&p_gugun_cd=&in_distance=0&in_biz_cd=&isError=true&searchType=C&set_date=&all_store=0&whcroad_yn=0&P90=0&new_bool=0&iend=1000"
post_params <- parse_url(sprintf("%s?%s", url, payload))$query
res_content <- POST(url, body = post_params)
res_object <- fromJSON(content(res_content, "text"))
# 시도 코드와 이르을 받아서 주소목록이 들어 있는 data.frame을 리턴하는 함수
get_addrs <- function(sido_cd, sido_nm) {
  url <- "https://www.starbucks.co.kr/store/getStore.do"
  payload <- sprintf("in_biz_cds=0&in_scodes=0&search_text=&p_sido_cd=%s&p_gugun_cd=&in_distance=0&in_biz_cd=&isError=true&searchType=C&set_date=&all_store=0&whcroad_yn=0&P90=0&new_bool=0&iend=10000", sido_cd)
  post_params <- parse_url(sprintf("%s?%s", url, payload))$query
  res_content <- POST(url, body = post_params)
  res_object <- fromJSON(content(res_content, "text"))
  cbind(rep(sido_cd, length(res_object$list$addr)), rep(sido_nm, length(res_object$list$addr)), res_object$list$addr)
}
# 데이터랭글링
# install.packags(c("tidyverse", "stringi"))
library(tibble)
library(dplyr, warn.conflicts = FALSE)
library(stringi)
df <- sido_items |> rowwise() |> mutate(addr=list(get_addrs(sido_cd, sido_nm)))
tbl <- do.call(rbind.data.frame, df$addr)
names(tbl) <- c("sido_cd", "sido_nm", "addr")
tbl <- tbl |> rowwise() |> mutate(addrsplit=stri_split_fixed(addr, " ", 4))
tbl <- as_tibble(do.call(rbind.data.frame, tbl$addrsplit))
names(tbl) <- c( "sido", "gugun", "dong", "bunji")
tbl |> count()  # 전체 매장 개수
stat_sido <- tbl |> count(sido) |> arrange(desc(n))  # 시도별 매장 수
stat_gugun <- tbl |> count(sido, gugun) |> arrange(desc(n)) |> mutate(sido_gugun=paste(sido, " ", gugun))  # 시도별 매장 수
# 시각화
library(ggplot2)
p <- ggplot(stat_sido, aes(x =reorder(sido, n), y = n)) +
  geom_col(aes(fill = n), width = 0.7)
p <- p + coord_flip()
p <- p + xlab('시/도')
p
p <- ggplot(head(stat_gugun, 20), aes(x =reorder(sido_gugun, n), y = n)) +
  geom_col(aes(fill = n), width = 0.7)
p <- p + coord_flip()
p <- p + xlab('구/군')
p
# 데이터 출처: # https://kosis.kr/statHtml/statHtml.do?orgId=101&tblId=DT_1B040A3&checkFlag=N
pop_sido_text_data <- "sido,total,male,female
서울특별시,9505926,4615631,4890295
부산광역시,3348874,1638207,1710667
대구광역시,2383858,1174667,1209191
인천광역시,2949150,1476663,1472487
광주광역시,1441636,713037,728599
대전광역시,1451272,724026,727246
울산광역시,1121100,575939,545161
세종특별자치시,374377,186907,187470
경기도,13571450,6830317,6741133
강원도,1538660,774315,764345
충청북도,1597097,810548,786549
충청남도,2118638,1083242,1035396
전라북도,1785392,888291,897101
전라남도,1832604,922190,910414
경상북도,2624310,1322509,1301801
경상남도,3311438,1666968,1644470
제주특별자치도,676691,339071,337620
"
pop_sido_tbl <- read.csv(textConnection(pop_sido_text_data))
sido_tbl <- pop_sido_tbl |> inner_join(stat_sido, by = "sido")
# 상관계수
cor(sido_tbl$n, sido_tbl$total)
# 결괏값: 0.8926678
cor.test(sido_tbl$n, sido_tbl$total)

여기까지 입니다.

R언어 “Happy New Year 2022″를 출력하는 재밌는 코드

“Happy New Year 2022″를 출력하는 재밌는 코드입니다.

코드를 실행해 보세요.

seeds <- c(2219868, 10641, 443238, 9487)
word_lengths <- c(5, 3, 4, 4)
choices <- list(letters, letters, letters, 0:9)

magic_message <- function(seed, word_length, choices) {
  set.seed(seed)
  sample(choices, size = word_length, replace = TRUE) |>
    paste(collapse = "") |>
    stringr::str_to_title()
}

purrr::pmap_chr(list(seeds, word_lengths, choices), magic_message) |> cat()

R – yaml 파일 읽어오기

R로 작성한 script에서 가끔 복잡한 설정들 읽어야 할 때가 있습니다. 여러 방법을 사용할 수 있겠지만 설정파일을 만들어 놓고 읽어서 사용하는 방식을 선호하는데 예전에는 json 포맷을 설정으로 쓰다가 너무 너저분해서 이번에 yaml으로 바꿔봤습니다.

R이 너저분해지는 이유가  이런 종류의 tree 구조의 파일을 읽어서 자료구조로 바꿀때 R에서는 list 타입을 사용해서 맵핑하게 되는데 list의 하위 아이템이 1개인 경우 다른 랭귀지와는 많이 다르게 굉장히 복잡해 집니다. 이렇게 복잡한 이유가 R에는 모든 데이터타입이 기본적으로 vector 취급되기 때문입니다.

그런데 yaml을 사용해보니 json을 사용할 때보다는 데이터타입을 훨씬 잘 변환해 주는 것 같습니다.

패키지는 yaml을 설치해서 사용하면됩니다.
전체 코드는 아래에 있습니다.

# install.packages("yaml")
require(yaml)
configuration = yaml.load_file("d:\\workspace\\test_configuration.yaml")

print(configuration)
is(configuration)  # configuration 심볼의 타입 확인

print(configuration$var_0001)  # 각각 하위 요소들의 내용 확인
print(configuration$var_0001$var_0001_01)  # 각각 하위 요소들의 내용 확인

configuration$var_0001$var_0001_01[[1]]  # 이건 여전히 문제
is(configuration$var_0001$var_0001_01[['var_0001_01_01']])
is(configuration$var_0001$var_0001_01[['var_0001_01_02']])

print(configuration$var_0002)
print(configuration$var_0003)
print(is(configuration$var_0003))

test_configuratino.yml 파일의 내용

var_0001:
  var_0001_01:
    var_0001_01_01: "value_0001_01_01"
    var_0001_01_02: "value_0001_01_02"
var_0002:
  - "value0002_1"
  - "value0002_2"
  - "value0002_3"
  - "value0002_4"
  - "value0002_5"
var_0003: True

주의할 것은 하위 항목이 1개인 것은 여전히 [[1]] index를 지정해주지 않으면 안됩니다. 그래도 JSON보다는 훨씬 쓰기도 편하고 좋은것 같습니다.

R – 변수에 값을 넣고 바로 결과를 출력하기

제목대로 입니다. 정말 별것 아닙니다. 아주 가끔 유용하게 쓸 때가 있습니다.

variable <- 2 * 3
(variable <- 2 * 3)

핵심은 2번째 줄입니다.

직접 실행해 보세요.

예전에 어떤 R 전문가들이 모여서 토론하는 메일링리스트에서 저렇게 쓰는 것을 본 적이 있어서 기억하고 있었습니다.

원리는 간단하면서도 오묘한데 R의 구조를 이해하는데도 도움이 됩니다.

R은 값을 가진 symbol이나 값 자체를 호출하게 되면 기본으로 print함수가 호출되어서 심볼의 내용을 출력하게 되어 있습니다. 그런데 <- 나 = 로 변수대입(실제로는 심볼지정)을 하게 되면 print는 기본으로 작동하지 않습니다.

그래서 연산자 심볼인 소괄호로 묶어주면 최종 연산된 값이 리턴되고 바로 print까지 실행됩니다.

저걸 쓸 일이 있겠나 싶겠지만 정말 가끔 쓸 일이 있어요. ^ㅡ^;;;


위에 제가 이해를 위해서 연산자라고 적었는데 오해의 여지가 있지 않을까하는 걱정에 내용을 추가합니다.

R에는 연산자가 없습니다. (아마도…)
다음 코드를 실행하고 결과를 확인해 보세요.

is(`[`)  # 얘는 펑션
`[`

is(`(`)  # 얘도 평션
`(`

is(`<-`)  # 얘도 평션
is(`=`)  # 얘도 평션

is(`]`)  # 하지만 얘는 펑션이 아님
`]`

is(`)`)  # 얘도 아님
`)`

닫는 괄호들은 무슨 타입인지 잘 모르겠지만 함수도 아니고 일반 심볼도 아닙니다.  아마 표현문 종료 기호같은 R 내부에서는 어떻게 취급되는지 모르겠습니다.

다음 코드도 한 번 실행해 보세요.

e <- parse(text="(1+2)")
e[1][[1]][[1]]
e[1][[1]][[2]]
e[1][[1]][[3]]
e[1][[1]][[4]]

결과는 직접 확인해 보세요.
이걸 이해하셨다면 R의 내부구조를 많이 이해한 것이 됩니다.

RStudio v1.0 릴리즈

요 며칠 사이에 R관련 커뮤니티에서 새소식으로 메일이 날아오고 있는데 가장 많이 보이는 것이 RStduio v1.0이 릴리즈 되었다는 것입니다.
바꿔 말하면 그동안 RStduio의 버전이 0.x대 였다는 것이지요.
2011년 2월에 0.92로 메이저(major) 릴리즈가 공개되고 2016년 11월 2일에 버전 1.0을 넘기게 되었습니다. 오래 걸렸네요.

중요한 업데이트 내용은 공식 블로그를 보시면 되겠습니다.
https://blog.rstudio.org/ 여기를 가보시면 되지만
귀찮아 하실 분들을 위해서 업데이트 내용을 간단히 정리해 보면 다음과 같습니다.

R Notebooks 지원

iptyhon-notebook이나 기타 다른 분석 인터페이스에서 유행처럼 지원하는 notebook 기능을 지원합니다. 단 포맷이 Rmd(R markdown 형식) 이므로 다른 노트북 보다는 더 유연한다고 할 수 있습니다. Rmd파일을 그대로 Notebook으로 인식합니다.

물론 R은 원래 반 대화형 모드(interactive mode)로 코드의 중간부분만 선택해서 따로 실행할 수 있기 때문에 Notebook 기능을 지원하지 않아도 노트북 흉내를 낼 수 있었습니다.
R Notebook은 다른 노트북 처럼 입력창의 중간중간에 결과를 확인할 수 있다는 장점이 있어 훨씬 직관적입니다.
이제 Notebook 흉내가 아닌 Notebook 기능을 그대로 쓸 수 있습니다.
chunk(청크; R markdown내에 듬성듬성 있는 R코드 영역)에 대한 부분만 따로 실행하거나 전체를 실행해서 preview하거나 할 수 있습니다.

그 외에도 노트북은 수식이나 문장 사이에 삽입하는 코드들에 대한 대화형 모드를 같이 지원합니다.

위 그림과 같이 LaTex으로 수식을 입력하는 등의 것들입니다.

Spark with sparklyr

sparkyr 패키지를 이용해 Spark(스파크)를 지원합니다. Spark내에 있는 dataframe을 RStduio에서 미리보기 하거나 할 수 있다고 합니다.
아직 테스트 해보지는 않았지만 조만간 해봐야겠습니다.

Profvis 패키지를 이용한 프로파일링

보통의 다른 랭귀지들은 IDE(통합개별환경)에서나 또는 별도의 도구를 이용해서 profiling(프로파일링)을 할 수 있습니다.
실행되는 코드중에서 어느 부분이 얼마만큼의 시간과 자원을 소비하는지에 대한 트레이싱인데 RStduio가 이제 profiling을 지원한다는 얘기입니다.
어느 구간에서 가장 오랜 시간이 걸렸는지 시각화해서 보여줍니다.

화면은 대충 아래와 같습니다.

코드를 입력하고 코드를 선택한 후에 Profile 메뉴를 눌러주면 됩니다. (어렵지 않아요.^ㅡ^)

Data Import(데이터 적재) 기능 강화

File 메뉴의 Data Import 메뉴를 이용해서 File이나 URL에 대한 파일의 미리보기 기능을 지원합니다. 하지만, 공식 블로그에 적힌 예제를 실행했더니 에러가 나더군요.
파일에 따라 에러가 발생하는지 아닌지는 확인해 보지 않았습니다.
제 작업환경이 이상한 것인지도 모릅니다. 버그라면 뭐 나중에 고쳐주겠죠. (우선 포기…)

그외에 다른 기능에 대한 내용은 없습니다. RStduio 최신 버전을 유지하고 계셨다면 위에 열거된 내용 빼고는 큰 차이는 없어 보입니다.
그리고 더불어서 RStudio Server도 v1.0을 넘겼습니다. 공식 블로그에서는 따로 언급이 없지만 위에 기능들이 함께 지원되었을 가능성이 큽니다.

Reproducible Research – 재현가능연구

Reproducible Research에 대한 포스팅입니다.

이게 뭔지? 어떻게 하는 것인지? 이런 것들에 대한 내용입니다.

Reproducible Research는 연구나 분석을 할 때 사용한 코드, 데이터, 리포트를 한꺼번에 넣어서 다른 사람들이 받으면 그대로 재현이 가능하도록 하게 배포하고 공유하자는 계몽운동입니다.

어헐… 리서치 분야의 새마을운동인가?

사실 히스토리는 꽤 오래되었습니다. 17세기 부터라고 하는데 그 시대 사람이 아니어서 모르겠구요.
제가 알고 있는 최근 관련 사건은 2006년 Duke 대학의 논문(암세포 관련) 사건인데, 배포된 논문을 재현하는데 시간이 너무 걸려서 문제점을 나중에야 발견했고 그 사이에 그 논문을 근거로 시작한 연구 5개가 졸지에 중단된 사건입니다.

코드와 데이터와 리포트를 한꺼번에 배포하는 것이라고 했는데.
그러면 “Reproducible Research는 코드하고 데이터하고 PDF를 한꺼번에 압축해서 주면 되는거네?” 라고 생각할 수 있습니다.

그렇게 하는 사람도 아직 많습니다. ^^. 하지만 핵심요체는 이런걸 더 쉽게 하자는 것이고 피드백도 쉽게 받을 수 있어야 한다는 것입니다.

Reproducible Research는 소프트웨어 구현체를 위한 개발소스를 배포하는 것에 대한 것이 아닙니다. 단편적인 예로 논문을 배포할 때 논문에 사용한 코드와 데이터와 설명을 한꺼번에 배포하는 것 정도로 이해하면 빠를 것 같습니다.

압축파일로 전달하거나 하는 것은 완전히 종료된 연구결과는 그렇게 해도 되겠지만 어떤 것들은 자신의 연구 결과물도 계속 고쳐나갈 수도 있기 때문에 그렇게 하면 번거롭습니다. 그래서 코드를 계속 형상관리하고 자동으로 생성해서 배포하려고 많이 합니다.

우선 하기전에 몇가지 의문에 대해서 살펴보면…

어느 분야에서 쓰는 것이냐?

  • 연구소, 아카데미 등 학술쪽이 메인입니다.

    각종 논문 양산소들

  • 데이터 분석

    굉장히 좋습니다.

  • 데이터 사이언스

    설마 데이터 사이언스가 주구장창 구현체 개발만 하는 것이 아니라면…

꼭 논문을 쓰거나 어떤 연구소에서 연구를 하는데만 쓰는 것은 아닙니다. 메인이 그쪽이이긴 하지만 인터넷기반의 온라인의 발달로 R&D쪽과 관련이 있다면 모두 해당됩니다.

흐름상 꼭 해야 하는 거야?

남들이 한다고 다 따라할 필요는 없다고 봅니다만 흐름이 있는 것은 분명합니다. 꼭 해야 하는 것은 아니지만 어느덧 많은 사람들이 자기의 연구결과나 분석결과를 온라인에 배포하는 것이 일상화되었습니다.

내 피땀어린 연구물을 왜 배포 하나?

  • 첫번째는 Personal Branding 이유가 많아 보입니다. 어필하는 것이지요. 개인을 상품화
  • 두번째는 연구물을 공유해서 다른 사람들의 피드백을 받음으로써 자기 발전에도 도움이 된다고 생각하는 것입니다
  • 세번째는 논문 점수… 패쓰!

개인의 취향이고 하기 싫으면 안해도 되지만 추세는 배포해서 검증도 받고 성과도 알리는 것입니다. 일종의 자신감 표현일 수도 있고 우물안 개구리로 살지 않겠다는 생각일 수도 있겠구요.

배포를 걱정하는 이유가 내가 고생해서 연구한 것을 왜 남에게 거저 주느냐? 라는 이유일텐데요. 자신의 연구 결과물이 매우 좋다면 배포를 당연히 하지 않겠지요. 하지만 그런 뛰어난 결과물을 만드는 경우가 얼마나 될까요?

내 연구물은 약간의 불가피한 어쩔수 없이 안타깝고 애절한 이유로 조작을 했기 때문에 다른 사람들이 절대 재현해서는 안돼! 아~ 님! 그러시면 안돼요!

Reproducible Research에 필요한 것

온라인 IT활용능력이 필요합니다. 압축파일을 USB에 담아서 주는 세상이 어느덧 지나버린 것 같습니다.

형상관리 또는 코드 보관용 스토리지

보통 리서치를 전문으로 하시는 연구원들을 보면 연구성과물의 백업에 대해 예민한데요. 당연한것 이 성과물이 날아가면 인생이 과거로 회귀하기 때문입니다.

지능은 그대로 나이는 젊어지는 그런 회귀가 아니라 나이는 그대로 성과는 예전으로 돌아가는 회귀. @.@

보통 Reproducible Research에서는 온라인 소스코드 레파지토리를 많이 사용합니다.

물리백업은 외장하드를 여러개 사용하시던지 스토리지를 쓰시던지 각자의 방법이 있잖아요?

많이 발견되는 순서대로 보면

  • Github: 공짜인데 private은 돈 받아요
  • Bitbucket: 공짜인데 private 1개 공짜. 추가는 돈 받아요
  • Dropbox: 형상관리는 아니지만 물리백업의 위험을 최소화하기 위해서
  • 기타: 찾아보면 더러 있습니다.

private repository는 남들에게 안 보이게 숨기는 레파지토리입니다.

온라인을 사용하는 이유는 링크만 던져줘도 자료를 쉽게 공유할 수 있기 때문입니다. 게다가 삭제해도 복원이 가능하고 매우 안정적입니다. 대신 형상관리 소프트웨어를 사용하는 방법을 익혀야 하겠지요. SVN, CVS, GIT 등을 잘 쓰신다면 문제가 별로 없습니다.

살펴보면 대체로 Github을 많이 쓰는 것 같습니다.

형상관리를 회사나 연구소내에서 따로 구축해서 사용하는 경우도 많은데요 백업이나 관리가 잘 되야 하겠지요. 자료를 찾아 보시면 구축하는 방법등이 잘 나와 있습니다.

내부 형상관리가 통째로 날아가면 연구소 폐쇄 또는 폐업… 하지는 않더라구요.

데이터 배포용 레파지토리

연구물을 배포할 때 코드와 함께 사용한 데이터를 같이 주어야 하는데요. 알고리즘을 만들거나 분석기법을 만들거나 응용 분석을 하거나 해도 사용한 데이터가 있을 것입니다.
포함해야 하는 이유는 다른 사람이 재현을 해야하기 때문입니다. 코드만 가지고는 정확히 재현이 안되니까요.

데이터를 배포하는 방법은 크기나 데이터의 출처에 따라 배포하는 방식이 달라집니다.

  • 데이터의 사이즈가 매우 작은 경우

    코드에 넣어 줍니다. 코드에 변환해서 넣는 것이 대부분 가능합니다. 최근에는 데이터들의 크기가 커지기 시작하면서 이 방법은 점점 어렵게 되고 있습니다.

  • 데이터가 오픈데이터인 경우

    오픈데이터는 공개된 곳의 링크를 걸어주면 됩니다. 보통 코드내에서 자동으로 오픈데이터를 긁어오게 만들어 코드를 작성합니다.

  • 데이터가 매우 크고 오픈데이터가 아닌 경우

    웹사이트에 올리거나 Dropbox같은 클라우드 스토리지로 공유합니다. Dropbox외에도 Google Drive라든가 One Drive라든가 여러가지가 많습니다. 대부분 기본 용량은 공짜이고 용량 추가는 비용 지불입니다.

Reproducible Research 작성도구

분석 도구라면 뭐든지 가능하지만 우선 특화된 UI가 있는 분석툴들은 어렵습니다. R, Python, SAS, Matlab은 가능할 것입니다.

Excel로도 하긴합니다만 불편하더군요. 나 퀀트여서 C++, Excel만 하는데? 네.. 알아서 잘!

보통 R을 많이 사용하는 것을 볼 수 있는데요.
이유는 보통 이렇습니다.

  • 공짜입니다.

    받아보는 사람이 결과물을 보기 위해서 소프트웨어를 구매해야 한다면 힘드니까요. 나 오라클에 SQL로 코드짜고 연구했어. 그래서 내가 너에게 오라클 라이센스를 주마! 네! 님짱!

  • 코드가 간결하고 분석이나 리서치하기에 편합니다.

    원래 그런 용도로에 많이 특화되어 있습니다. 나 perl로 무지 간결하게 짤 수 있는데 대신 난독화가 심해져서 읽는 것은 너의 능력문제야! 네! 님짱!

  • 코드와 설명을 함께 넣어 리포트를 쉽게 만들 수 있습니다.

    Sweave나 Knitr같은 패키지로 쉽게 가능합니다. 코드에 주석으로 설명을 적기에는 너무 부담도 크고 할일도 많지요. 보고서나 논문 형태로 포맷팅을 쉽게 할 수 있습니다.

분석결과물이 코드와 데이터만 있는 것이 아니라 설명이 들어 있어야 하는데요. 보통 논문같은 형식이나 보고서 형식을 생각하시면 됩니다. 코드와 데이터만 덜렁 주지는 않습니다.

이정도 코드는 알아보겠지? 하실 수도 있겠지만 간단한 것을 제외하고 내가 만든 알고리즘이나 데이터 분석 절차와 대응 방법을 받는 사람이 쉽게 이해하기 어려우니까요.

참고로 위의 요소를 만족하는 도구로 대안은 Python, Ruby가 있습니다. 그 이유가 전부인 것은 아니지만 저런 이유도 있어서 데이터 사이언티스트가 많이 쓰는 도구로 Python, R이 상위권이기도 합니다.

Reproducible Research 배포처

준비를 다 했다면 배포할 곳이 필요합니다.

헐 @.@ 나는 누군가? 지금까지 뭘 했는가?

학회에 논문 제출?도 하겠지만 그 외는 온라인 커뮤니티에 배포를 많이 하게 되는데요. 커뮤니티에 배포를 하더라도 링크를 주고 링크를 누르면 어떤 사이트로 이동해서 결과물을 보게 하는데요. 그래서 결국 웹사이트가 필요합니다.

네. 도메인따고. 호스팅받고. 설치하고. 세팅하고. 하고. 하고. 하고…

웹블로그는 공짜가 많습니다. 괜찮은 것 하나를 선택해서 쓰면 됩니다. 도메인을 구매해서 연결하는 것도 좋습니다.
많이 쓰는 것으로는 다음과 같은 것들이 있습니다.

  • WordPress 또는 다른 블로그

    Tumblr나 Scriptogr.am 등 많습니다만 WordPress가 가장 만만해요. 공짜로 도메인 연결도 해주는 곳이 많습니다.

  • Github

    웹페이지를 볼 수 있게 지원합니다. 공짜로 도메인 연결도 가능해요. 다른 것들도 있습니다만 Github이 가장 만만해요.

  • 개인 웹사이트

    생각보다 많습니다. 클라우드를 이용해서 쉽게 구축하는 서비스를 제공하는 곳도 많습니다.

이런 추세는 R로 Reproducible Research를 하는 사람들의 트렌드때문인데요. R의 Knitr가 WordPress로 리포트를 배포하는 기능을 지원하기 때문입니다. Rmarkdown을 작성해서 배포하면 WordPress로 플롯과 코드와 설명이 모두 배포됩니다.

Github을 이용하려면 HTML 코드를 작성해서 업로드 해야 하는데 Knitr, Jekyll 조합으로 가능합니다. 요건 설정하기가 조금 까다롭습니다.

많이 알려진 플로우

Reproducible Research는 R 사용자들이 많이 주도하고 있는 상황이라서 R과 관련된 것이 아직까지는 대부분입니다.

많이 쓰는 플로우입니다.

  1. R과 Rstudio를 설치합니다.
  2. Rmarkdown이나 Sweave 형식으로 작성합니다.
  3. 작업하면서 소스코드를 계속 형상관리에 저장합니다.
    1. Github, Bitbucket, …
  4. 사용한 데이터는 오픈 스토리지에 올려 놓습니다.
    1. Dropbox, One Drive, Google Drive, Drive.., Drive.., …
  5. 리포트를 빌드합니다.
    1. 잘되는지 확인해야 합니다.
  6. 배포합니다.
    • WordPress로 배포
    • 또는 Jekyll로 빌드해서 Github에 Push

Reproducible Research 준비가 사실 번거롭고 할 일이 많습니다. 그런데도 하는 사람이 많은 것을 보면 신기하기도 합니다. 이 유행이 언제까지 일지는 모르겠지만 제 생각에는 그래도 앞으로도 당분간은 계속 될 것 같습니다.

세상이 너무 빨리 바뀌고 있네요.

R과 SAS 비교

이 포스트를 올린 이유가 일을 하다보면 초등학생 질문처럼 “호랑이랑 사자가 싸우면 누가이겨요?” 라고 물어보는 분들이 많기 때문입니다.

비교라기보다는 외국의 커뮤니티들에서 몇 년 동안 지속적으로 논쟁중인 내용의 댓글과 반박글을 중요한 것만 뽑아 정리한 것입니다.
중복되거나 비슷한 내용은 한꺼번에 몰아 넣었습니다.
이 논쟁은 어차피 결론이 안 날 것 같습니다만 쭉 한 번 읽어보면 R과 SAS 중 하나를 선택 하는데 도움이 될 것이라고 생각합니다.
밑에 요점 정리들 해 두었으므로 읽을 시간이 없으시면 그냥 요점으로 넘어가셔도 됩니다.
요점은 제 의견이 들어 있습니다. 어디까지나 제 의견입니다.

SAS가 낫다는 의견들 모음

  • R이 가지고 있는 메모리 사용 제약은 실제로 문제가 된다. 인메모리(in-memory) 기반인 R은 한 번에 다룰 수 있는 데이터셋(dataset)의 행과 열(rows와 column) 수의 제약을 가지고 있는데 (메모리의 제약으로 인해), 이 문제가 금방 해결될 것이라고는 보지 않는다

어차피 SAS도 인메모리(in-memory) 방식이기 때문에 SAS가 우위에 있다고 보기 힘들다는 반론이 있습니다. 다만 SAS가 보조도구를 지원하는 것이 있어서 어쨌든 사용성 관점에서는 더 낫다는 재반론적인 의견도 있습니다. R의 in-memory제약에 대한 해결 부분은 다른 의견에서 반박 의견이 더 있습니다. 물론 R로 인터페이싱만 하고 Hadoop에서 map/reduce같은 것으로 실행하면 해결되는 알고리즘도 있지만 상당히 많은 통계, 분석, 데이터마이닝 알고리즘들은 분산 컴퓨팅용으로 바꾸기가 어렵습니다. 추가로 R의 행과 열의 제한은 메모리가 충분함에도 불구하고 언어 자체에서 제한해 놓은 것 때문인데 지금은 그 제약이 없어 졌습니다.

  • 내가 보기에는 실제 대학에서는 R을 사용해서 강의를 많이 하거나 엑셀(Excel) 데이터를 SAS로 빨리 전환해서 분석하는 것을 가르치는 두 가지 타입이 많은 듯 하다. 많은 미국대학에서는 SAS를 무료로 사용할 수 있다. 하지만 대부부의 대학 교수들은 SAS보다는 R을 선호하는데 그 이유는 그 사람들이 R을 기본으로 학습 받았기 때문이다. SAS를 왜 안가르치는지 모르겠다.

젊은 교수들이 R밖에 쓰지 못하기 때문에 학생들에게도 R을 가르치고 그래서 시장에서 원하는 SAS 사용자가 최근에는 안 늘고 있다는 투덜거림입니다. 최근 추세를 보면 그런것도 같습니다. 제 생각에는 학교에서 굳이 비싼 상용툴로 학생들을 괴롭힐 이유가 없다고 봅니다.

  • SAS는 구인시장(Job Market)에서 아직도 가장 유용하고 뜨겁다 (hot). 지금까지 가장 많이 분석업무에 적용되어 왔으며 사례(case)가 많다. 하지만 R은 아직 성공사례(success story)가 많지 않다.

여기에 대해서는 R의 구인시장에서 리쿠르팅이 빠르게 증가하고 있다는 반박의견이 있습니다. 출처가 있었는데 놓쳐 버려서 찾을 수가 없군요. 어쨌든 아직은 SAS와 관련된 인력을 구인하는 곳이 많은 것으로 보입니다.  성공사례를 찾기는 어렵지만 실패사례도 없으며 미국 공공기관에서도 R을 도입해서 사용하고 있습니다.

  • 데이터 분석에서 80%가 지저분한 데이터(dirty data)를 깔끔한 데이터(clean data)로 바꾸는 등의 데이터 전처리(data manipulation) 작업 인데 R은 많은 데이터 전처리 기능을 제공하지 않으며 R과 SQL은 이런 일에 그리 유용하지 않다고 본다.

R의 강점이 data manipulation인데 왜 유용하지 않다고 하는 것이냐는 반박의견이 있습니다만 R의 문법이 SAS에 비해서 다소 어렵고 SAS쪽에서는 다른 GUI기반의 보조 제품들이 있기 때문에 한 말 같습니다. 데이터 분석 작업에서 시간이 소요 되는 작업의 80%는 데이터를 전처리하는 wrangling 또는 munging이라는 작업입니다. (제 생각도 그렇습니다) 이 부분을 어떻게든 빠르게 할 수 있으면 좋겠지만 많이 이 부분에 시간이 소요된다는 것에 대해서는 반론이 없습니다.이 부분은 숙련도의 차이라고 생각합니다. 또 SAS의 SQL 기능만 쓰는 사람도 많습니다.

  • 아카데미에서 SAS에 비해서 R을 많이 가르치지 않는 것은 구직 문제 때문이다. 많은 구직 오퍼가 여전히 SAS에 대한 것이기 때문이다.

이 얘기에 대해서 필드에서 오래된 숙련가 한 사람은 최근에 대학에서는 R을 베이스로 가르치는 곳이 훨씬 더 많다고 말합니다. 온라인상에서도 오픈된 여러 교재들을 보면 최근에는 R을 베이스로 가르치는 학교가 더 많아 보입니다. 말한 사람이 협소한 정보를 가지고 있는 것 같습니다.

위와 관련되어서 다른 얘기로 유럽의 많은 학교에서는 R을 베이스로 가르치기 때문에 오히려 이들에게 SAS를 훈련시키는 비용이 꽤 소모된다는 반론이 있습니다.

참고자료: http://bigcomputing.blogspot.com/2011/07/figuring-out-number-of-r-users-in.html
다만 R과 SAS를 단순 비교하기 어려운 것은 SAS는 R이 지원하지 않는 많은 것들을 지원한다는데 있다는 것(사용성이 좋은 기능들과 기타 여러가지 부수 제품들이야기입니다. 비용은 별개이구요) 이고 R은 통계 및 분석의 좋은 기초 환경이라는 차이가 있다고 말하고도 있습니다.

다시 위에 대한 반론으로 과연 SAS는 가지고 있지만 R은 가지고 있지 않은 기능이 뭔지에 대한 나열이 필요하다는 의문제기가 있습니다. 기능적인 이야기인지 제공하는 알고리즘의 이야기인지에 대한 것을 포함해서입니다. 모호하고 개인적으로 기준이 다를 수 있어 왜곡의 여지가 있습니다만 SAS가 역시 사용하기 편리하다는 의견은 많은 것 같습니다. 일단 GUI방식의 JMP(SAS사에서 판매하는 GUI기반 분석툴) 얘기가 많이 나옵니다. R은 좋은 GUI frontend가 별로 없습니다.  R의원형이 splus라는 아주 오래된 랭귀지이고 그 당시에는 그걸 생각할 겨를이 없었기 때문입니다. GUI가 필요하다면 R은 유리하지 않습니다.

  • SAS의 문제는 비용이 든다는 문제가 있고 R의 문제는 케이스에 따라 문제 해결의 난이도가 다르다는 문제가 있다. R은 문제해결을 위해서 많은 패키지들 설치해야 하고 때로는 패키지를 직접 고쳐야 한다. 특히 SAS로는 간단히 해결할 수 있는 몇가지 것들도 R로는 복잡하게 해야 한다. 적어도 잘 알려진 문제 해결과 처리 속도의 관점에서는 SAS가 낫다. SAS는 사용자친화적(user friendly)하지만 R은 아니다.

익숙함의 차이가 있을 수도 있겠습니다만 아주 틀린 말은 아니라고 생각합니다. R은 진입장벽이 조금 높습니다.  그리고 문제가 발생해도 징징거릴 수 있는 대상이 없습니다.

  • R의 패키지가 5300개가 넘는데 개인개발자(contrbutor)들이 만든 것들이라 대부분 테스트가 충분히 된것이 아니고 지원도 결국 만든 사람이 해야 해서 위험하다는 의견입니다.

반대 의견으로 SAS에서는 그럼 개인 개발자들이 알고리즘이나 패키지들을 만들어서 필요한 것들을 공급할 수 있는가를 묻는 것들이 있습니다. 필요한 것이 있는데 SAS에 없으면 못쓴다는 얘기가 되는데 그럼 어떻게 할 것인가? 라는 말입니다. 그리고 모든 R패키지들이 같은 상태로 관리가 안되거나 하지 않고 패키지들의 중요에 따라 잘 되는 것도 있고 아닌 것도 있다는 의견입니다. 후에 이 의견에 대한 재반박의견으로 IML을 이용하면 만들수는 있다는 의견이 있습니다.
더불어 말씀드리면 R의 패키지들을 만드는 사람들 중에는 이름 모를 사람들도 많지만 유명한 통계학자들도 많습니다. 패키지의 품질이 떨어지고 버그가 있는 것은 패키지와 만드는 사람에 따라 달라지는 문제이지 R패키지가 모조리 다 그런것은 아닙니다.

  • SAS는 Marix연산에 있어서 다중쓰레드(multi-thread)를 지원하고 많이 테스트되어서 안정적이다.

이 말을 한 사람은 SAS 세일즈맨이 틀림없다고 비꼬며, R은 안될 것이라고 생각해서 말했겠지만 R에서도 당연히 된다는 반론이 있습니다. (네 당연히 됩니다)

  • 혹시라도 SAS가 지원을 끊는다면 지속되기 어렵다는 문제가 있지만 오픈소스는 그렇지 않다. Windows XP의 경우를 빗대어 보더라도 그렇다.

이 의견에 대해서 30년동안 이 계통에서 일을 해왔지만 Windows XP를 예로든 것은 맞지 않다고 보며, SAS와 R이 대체 뭐가 다른지 모르겠고 분석 시스템의 문제는 IT operater와의 커뮤니케이션 문제이고, 또 단지 테크니칼 문제일 뿐이다라고 일축하고 있습니다.
SAS가 좋고 R이 좋고하는 분석과 상관없는 얘기라는 것인데요. 구축과 소프트웨어의 유지도 회사의 자체 문제라서 관점에 따라서는 맞는 얘기이지만 도입하는 입장에서는 이 사람 얘기는 안 맞는 얘기라고 봅니다. R이 분석 시스템을 구축하는데 다소 유리하다는 말에 대해 다소 SAS를 옹호하는 입장의 말입니다. 제가 해석을 잘 못 했을 수도 있겠구요.

  • 원숭이는 SAS와 SPSS를 쓸 수 있지만 R을 사용하기 위해서는 전문가가 필요하다. 대부분의 회사들은 한 무리의 원숭이들이 전문가의 관리하에서 일하는 구조이므로 SAS와 SPSS같은 툴을 쓸 수 밖에 없다.

SAS쪽에 대해 안좋게 얘기하는 것 같아 보이지만 결국 SAS를 선택할 수 밖에 없는 중요한 이유 중에 하나라고 생각되서 이쪽으로 분류했습니다. 무슨 뜻인지는 아실 것이라고 생각합니다. 물론 저는 SAS를 사용하는 사람이 원숭이라고 말하고 싶지 않습니다. 그냥 R을 사용하지 않는 분석가들을 업신여기면서 징징거리고 있습니다만 결국 현실은 SAS를 써야 하는 경우가 많다는 말을 하고 있습니다.

R이 낫다는 의견들 모음

  • R은 가장 성공한 오픈소스프로젝트(open-source proejct) 중 하나이며 계속 발전해 나갈 것이라는 것은 자명하며 커뮤니티에 의해서 스탠다드로 계속 유지될 가능성이 높다.

주류가 될 것이긴 하지만 오픈소스가 대부분 그러하듯이 발전속도가 느려서 엔터프라이즈 시장의 요구에 빠르게 만족하지 못할 가능성이 크다는 반박 의견이 있습니다. 오픈 소스 프로젝트들 중에는 발전속도가 빠른 것도 있고 느린 것도 있습니다. 빨랐다가 중간에 느려진 것도 있구요. R은 이미 주류에 접어들었습니다. 오픈소스 중에 R을 대체할 만한 것이 현제는 python의 scipy 정도입니다마 상당한 차이가 있습니다.

  • 시장에서 통계분석을 매출액 증가의 목적으로 사용하거나 후에 회사 자체를 판매하기 위해서라면 R로 복잡한 시스템을 구축하는데 노력을 소비하기 보다는 잘 알려진 대중화된 툴을 선호하기 마련이다. 결국 SAS나 SAP등을 사용하게 되지 R이나 Excel with VBA로 복잡하게 구현된 것을 쓰려고 하지 않는다.

연구를 위한 기반기술로는 R을 유행이고 연구 목적의 기반으로 쓰겠지만 엔터프라이즈에서 분석 시스템을 구축할 때는 결국 SAS나 Matlab같은 것들을 쓰게 될 가능성이 여전히 크다는 의견입니다. 회사를 팔든 합병을 하든 매출액을 증가시키든 목적에 잘 부합하는 잘 알려진 것을 쓰라는 얘기입니다. 즉 협업이나 기존의 기득권 세력과 같이 작업을 하려면 SAS를 써야 한다는 말입니다.

하지만 R도 패키징을 통해서 구조화를 할 수 있기 때문에 큰 문제가 아니라는 반론이 있습니다. 회사의 비즈니스 유형에 따라 달라질 문제로 보여집니다.

  • R은 단순히 행렬처리를 위한 랭귀지라고 생각하지만 사실상 대부분의 데이터타입을 가지고 있는 full-set 랭귀지이고 속도 문제에 있어서는 rScaler같은 외부 패키지들을 사용할 수 있어서 해결할 수 있고 single thread에 대한 제한 문제도 동일한 방법으로 (패키지를 사용해서) 해결할 수 있다고 말합니다.

이 것은 R이 병렬처리가 안되고 속도가 느리다는 어떤 의견에 대한 반론입니다. 위에서 SAS 옹호론에 있는 얘기에 대한 반박글입니다.

  • SAS는 테스트가 잘 되어 있어서 버그가 없다는 말은 조크다. 실제로 이상한 코드를 SAS client에서 SAS server로 보내면 아무 메세지 없이 행이 걸리는데 6개월 동안 안고쳐지고 있다.

지금은 이 버그가 고쳐졌는지 모르겠지만 어느 소프트웨어나 버그는 있다는 얘기입니다. SAS가 버그가 없다고 주장하는 것은 완전 조크다라는 얘기입니다. SAS 손을 들어 주는 사람들이 버그가 적고 로버스트(robust)하다는 의견을 많이 제시한 것에 대한 반론입니다.

  • IBM에서 일하고 있는데 SPSS와 R, Python은 연동이 정말 잘 된다.
    > 묻어가기 스타일로 제품 홍보를 하고 있는 의견입니다. 이 내용과는 상관없지만 SPSS가 R연동을 선택한 것은 잘 한 일이라는 의견이 있습니다.

저도 그렇게 생각합니다.

  • R은 45000개의 펑션이 내장되어 있고 SAS는 15000개의 펑션이 내장되어 있는데 SAS는 지독하게 비싸면서도 너무 오만해서 도움도 잘 주지 않는다. 현재 학교에서 학생들은 R을 통해서 더 많은 지식들을 쌓아가고 있고 R 진영에도 상용 개발버전을 제공하는 회사가 있고 그런 회사들이 만든 R기반의 분석도구는 스케일러블(scalable)하고 로버스트(robust)하다.

결국 비싼 SAS를 써야할 이유가 별로 없다는 얘기로 보입니다.  하지만 R 상용화 도구도 아주 싸지는 않습니다.

SAS함수가 15000개라고 했는데 세어보니 1100개 정도라는 말이 있습니다. 하지만 분석외의 4GL기능이나 기타를 다 합치면 그 정도 된다는 군요. 하여튼 제공하는 기능에 비해서 너무 비싸다고 말하는 듯 합니다. (정말 비쌉니다)

반대 의견으로 나는 SAS에 있는 1000개로도 충분히 분석 잘 할 수 있고 지금까지 잘 살아왔다는 얘기도 있습니다.

  • SAS가 너무 느리게 procedure들을 추가해 주는 것 때문에 비난 받아온 것은 사실인데 사실 R은 오픈소스이고 커뮤니티 구성원중에 자신들이 만든 것을 공유하는 사람들이 많이 있는 반면에 SAS는 그렇지 않기 때문에 그런점에 있어서 SAS의 procedure가 더 적고 최신 알고리즘이 없다고 생각한다.

SAS IML로 충분히 새 알고리즘을 만들 수 있지만 잘 공유하려 하지 않기 때문에 다른 사람이 쉽게 얻을 수 없다는 것이네요. SAS의 알고리즘 지원 속도가 느린 것은 IML로 할 수도 있다라는 것 외에는 반론이 거의 없습니다.

  • R은 클라우드 서비스도 제공한다. 가격도 싸다.

SAS도 클라우드가 있다고 들었는데 사실 확인을 안해서 모르겠습니다. 다른 시스템에 연동하기에는 SAS 보다는 R이 더 유연한 것이 맞습니다. 안되면 뜯어 고쳐서라도 붙일 수가 있으니까요. 하지만 이 부분은 시스템 구축 적인 측면이지 분석적인 측면은 아닙니다. 미국 사람들은 분석 시스템과 분석 업무를 많이 구분하지 않는 것으로 보입니다.

모호한 의견들

  • R을 사용하려면 프로그래밍과 통계분석을 할 수 있는 사람이 필요하고 SAS는 엔지니어와 매니저만 있어도 사용할 수 있다. 하지만 SAS는 비용문제가 있고 만약 통계분석을 할 수 있는 사람이라면 R은 공짜다.

이 부분은 너무 잘 알려진 내용입니다. SAS의 JMP(이것도 따로 구매하는 유료 패키지인 것으로 아는데 확실치 않습니다)등을 이용하면 프로그래머의 도움없이 구축까지도 가능해서 매우 편리하다는 얘기가 있습니다. R을 사용하기를 원하는 커스터머는 주로 많은 프로그래머(IT인력)을 가지고 있지만 소프트웨어를 구매할 예산은 없는(또는 구매하고 싶어하지 않는) 고객이라는 얘기도 함께합니다. (경험상 이 이야기는 맞는 것 같습니다). 그리고 앞으로도 이런 고객들이 크게 늘 가능성이 많다고 주장합니다. 프로그래머는 싸고 소프트웨어 버짓은 점점 줄고 있다고 생각하는 의견 인데 미국쪽 커뮤니티 분위기를 살펴보면 이 경향은 맞는 것 같습니다.

  • SAS가 여전히 선호되고 있지만 이것은 너무 많이 알려져 있고 사람들이 보통 잘 알려진 브랜드가 좋다는 선입견과 오만을 가지고 있어서라는 선호하는 것이 아니냐는 의견이 있습니다. 때문에 사람들이 익숙한 것을 계속쓰고 그것으로 자신들의 문제를 쉽게 해결할 수 있으며 그것으로도 충분하다면 다른 것을 도입하는 것을 방해한다고 본다.

즉 익숙한 것으로 충분하다면 굳이 다른 것으로 전환하는 소모와 위험을 안으려 하지 않는다는 얘기입니다. 그냥 변화를 싫어하는 사람들이 많아서 생긴 문제라고 보는 것 같네요.

  • 회사환경에서 코드와 개발 기반의 시스템을 운영할 수 있는 역량이 된다고 볼 때 SAS의 정형화된 리포트나 분석방법이 아닌 다른 분석방법이나 커스터마이징된 것을 원한다면 R이 더 낫다

반대의 경우라면 SAS가 낫다는 얘기입니다. 즉 회사가 엔지니어(개발자)베이스인지 아닌지에 따라 다르고 원하는 자유도와 내재된 역량에 따라 달라 질 수 밖에 없다는 의견입니다.

  • SAS도 R처럼 확장을 만들어서 제공할 수 있다 하지만 R과 같이 중앙에서 관리하는 것은 없다.

http://www.ats.ucla.edu/stat/sas/code/ 같은 코드 공유 사이트를 충분히 운영할 수 있다고 이야기하고는 있지만 CRAN(R 패키지 제공 사이트)처럼 체계적으로 관리하지는 않다고 말합니다. 즉 SAS의 코드 신규 펑션이나 확장체를 구할 수 없는 것은 커뮤니티의 문제인데 R진영이 훨씬 잘하고 있다는 의견입니다. R을 조금 더 낫다고 말하는 듯 한 뉘앙스입니다.

  • 둘 다 써야 한다. SAS는 성숙해 있고 R은 다른 시스템과 통합하는데 유리하다. 특히 빅데이터 분석에서는 통합하기 쉬운 R이 더 유리하지만 그렇다고 해서 SAS가 불필요해진다고 보기에는 매우 어렵다. 결국은 기술적인 문제와 사용자에 따라 선택은 달라지게 마련이다.
  • 상용 소프트웨어와 오픈소스 중 어떤 것이 더 버그가 많은지는 수정과 코딩에 기울인 노력에 따르다. 버그에 대해서라면 어떤 것이라도 안전하지 않다.

SAS가 상용이고 개발 회사가 책임지므로 버그가 없다라던가 R이 오픈소스이기 때문에 오픈된 소스를 여러 사람이 지적하고 피드백을 주기 때문에 낫다는 의견을 한꺼번에 지적하는 이야기입니다. R쪽에 조금 유리한 의견이네요. 오픈 소스와 상용 소프트웨어의 비교에서 늘 나오는 얘기입니다.

  • 지긋지긋하다. 이 논쟁을 몇 년이나 계속 해야 하나?

어차피 이 논쟁은 아직 결말을 낼 수 없기 때문에 투덜거리는 얘기도 많이 있습니다. 별로 신경쓰지 않는 부류입니다. 둘 다 잘하는 사람이겠죠.

위의 내용 요약

어차피 결론이 안날 내용이고 계속 맴도는 내용입니다만 요약을 해보면 이렇습니다.

  • 개발과 분석을 동시에 할 수 있는 인적 자원이 있고 SAS비용문제가 크리티컬하고, 다양한 분석, 새로운 분석방법을 여러가지로 적용해 보고 싶으면 R을 선택한다.

IT 기반의 회사들이거나 IT개발 능력이 충분한 젊은 인력들 위주의 회사들에 대한 얘기입니다. 특히 스타트업이나 벤처 쪽이지요.

  • 위와는 환경이 다르고 다소 비용이 소요되더라도 안정적이고 기존부터 운영되어 왔던 토대에서 분석 시스템을 운영하고 싶으면 SAS를 선택한다.

주로 IT베이스가 아닌 전통적인 엔터프라이즈에 대한 얘기로 보여집니다. 그리고 비용문제가 해결된 경우입니다.

  • 가장 좋은 것은 둘 다 하는 것다.

어쨌든 둘 다 하면 좋지만 둘 다하기에는 SAS 라이센스 비용과 훈련 비용이 모두 소모되는 문제가 발생할 수도 있고, 반대로 잘 하면 둘의 장점을 합칠 수 있다라는 얘기입니다. 둘 다 하는 경우는 대부분 나중에 R로 넘어가는 경우가 많다고 알려져 있습니다.

정리

위의 논쟁들은 미국 상황이라 국내 환경과는 다소 거리감이 있습니다. 결론적으로는 아직 SAS의 우세이고 R이 기반을 장악해 나가는 추세입니다. 물론 완전히 대체하거나 한쪽이 끝판왕 되거나 소멸되거나 하지는 않을 것입니다.
사실 미국의 분위기를 보면 R을 사용하는 것에 대해 큰 거부감이 의외로 없습니다. (너는 너, 나는 나)
그렇다고 해서 SAS를 몽땅 R로 바꿀것이야 라고 말하지도 않습니다.
아래 의견은 저의 개인적인 의견입니다.

이제 경험에 비추어서 국내 환경을 정리해보면 국내 환경은 주로 SAS가 차지하고 남은 지위를 다른 분석 솔루션들이 차지하다가 최근에 조금씩 흔들어가는 모양새입니다. 그래서 주로 SAS를 다른 것으로 바꿀 수 있는가?에 대한 얘기가 많습니다.

국내 닷컴 컴퍼니

국내 인터넷 컴퍼니들 즉, 포털 및 웹서비스 업체들은 별 문제가 없어 보입니다. 특성상 되든 안되든 어차피 in-house로 해결하려 는 특성이 강합니다. SAS를 쓰고 있는 곳들은 계속 쓸 테고 구축은 SAS보다는 돈 안드는 오픈소스 쪽을 쓰려고 할 것입니다. 운영에 포커싱하는 경우가 많습니다. 역량도 충분한 곳이 많습니다. 물론 업체에 따라 전혀 아닌 곳도 있습니다.

여긴 그냥 R을 써야 합니다. 이유는 SAS가 너무 비싸고 자유롭게 다른 오픈소스와 연동하기 너무 어렵기 때문입니다. 특히 분석모듈을 어떤 플랫폼에 임베디드해야 하는 상황에서는요. 구현체를 구축해서 서비스 앞단 까지 바로 붙이고 테스트하고 전혀 새로운 모형을 만들어내고 하는 일을 빈번하게 해야하는데 자유도가 높은 것이 더 유리할 것입니다.

국내 일반 기업들

국내 엔터프라이즈쪽은 각각의 산업(industry)에 따라 조금 복잡해지는데, 이 기업들은 대부분 SAS를 이미 가지고 있습니다. 년간 라이센스를 지속적으로 지불하고 있는 곳들인데요. 산업에 따라 크게 2계통으로 나누고 R을 도입하는데 있어서 어프로치(approach)를 달리해야 하는 회사라고 할 수 있습니다.

서비스업 계통

국내 업체의 경우 SAS를 R 바꾸거나 또는 신규 도입시 R을 도입하려는 이유는 대부분 비용 때문이고 주도를 하는 곳은 IT쪽입니다. 분석 현업에서는 이미 도입되어 있고 적응이 되어 있는 SAS를 버리고 R로 바꾸려는 위험을 안고 싶어하지 않습니다. 위험한 해석일 수도 있지만 밥그릇 문제도 있겠구요. 대부분 IT쪽과 현업쪽이 충돌하거나 반발하게 되서 R을 도입하는 것은 슆지 않습니다. 결국 IT부서가 하는 것이 아니라 분석 현업이 SAS를 쓰든 R을 쓰든 해야 하기 때문입니다. 써야 하는 사람들이 일단 거부하기 때문에 강제를 하지 않으면 안되는 것인데 무작정 강제로 할 수는 없으므로 SAS와 R을 비교해와라는 지시를 내리고 지시받은 사람들은 업체에 시켜서 자료를 받은 다음 보고합니다. 보통 순서가 R의 단점을 부각시키며 위험성을 어필해서 SAS를 고수하는 사례가 많습니다.
R의 단점은 위의 논쟁들에서 나오긴 했지만, 어차피 공짜이므로 그냥 스스로 써도 되는데요. 아예 쓰면 안 될 도구처럼 표현하는 경우가 많습니다.

비즈니스 규모가 크고 IT역량이 충분하다면 R을 선택해 합니다. 이유는 비용때문입니다. 서비스규모가 커지면 분석 시스템도 커져야 하는데 그 비용이 상상을 초월하게 됩니다.

그렇다고 있는 SAS를 한꺼번에 버리면 충격이 크겠지요. 그럴 수는 없습니다.  긁어서 부스럼을  만들필요가 없지요.

그리고 비용문제가 없어도 R을 써야합니다. 이유는 연동 때문입니다. 특히 분석 모듈을 어딘가에 임베디드해야 하는 상황이거나 루즈하게 연동해서 당장 돌아가게 만드는 상황이 많다면 R을 쓰는 것이 아주 좋습니다.

비즈니스 규모가 작다면 Excel을 쓰세요. Excel 매우 훌륭합니다.

제조업 계통

하지만 복잡한 분석을 하지 않는 산업에서는 변화가 이루어지고 있습니다. 보통 제조업쪽입니다. 이런 SAS를 사용하고 있더라도 SAS의 많은 기능을 다 활용하지 않기 때문이고 분석 자체를 수행하지 않는 곳이 많습니다. SAS외에 제조 공정 관리에 더 적합한 분석 도구를 쓰는 곳도 많습니다. 사실 데이터 사이즈만 작으면 엑셀로도 충분히 가능한 곳도 많습니다.

SPC를 많이 하지 않거나 분석을 많이 하지 않을 것이라면 SAS를 그냥 써야 합니다.  안정적이고 검증되어 있고 좋습니다. 비용문제가 있다면 R이 아닌 다른 것으로 바꿔야 합니다. SPSS라든가 Matlab이라던가 인더스트리에 적합한 소프트웨어들이 많이 있습니다. 그래도 비용문제가 여전히 있다면 그때는 R이나 다른 것으로 바꿔야합니다. 하지만 최선의 선택이라고 말하기 어려울 것 같습니다.

계통을 초월한 대기업 그룹사

설명하기에는 복잡도가 최대입니다. 처음에는 설명을 안드리겠다고 적었지만 요청이 있어서 추가로 적어봅니다.

비용문제가 없다면 SAS를 써야합니다. 이유는 국내 대기업의 분석 조직 구성원들의 관성과 반발때문입니다. 대기업은 분석가들이 대부분 이미 SAS에 적응한 상태이며, SAS를 R로 바꾼다면 연습이 필요한데 그 반발이 상당하며, 또 SAS를 배워서 다른 회사에 그 특기로 입사한 사람들도 상당히 많습니다.
그 때문에 R로 전환하려는 노력을 잘 하지 많으며 R로 전환하려고 하면 밥그릇 문제로 전혀 협조를 하지 않습니다. 그래서 R 전환하는 프로젝트가 실패로 남거나 하는 시늉만 하기 일수입니다.
일부는 SAS로 하던것을 R로 하려는 사람들도 있지만 일부일 뿐이며 반발 세력의 파워를 이기지 못합니다. 이유는 대부분의 경우 SAS로 분석하나 R로 분석하나 결과 대부분 똑같기 때문입니다. 분석결과의 차이는 소프트웨어 차이가 아닌 분석기술의 차이입니다. 사람의 차이인 것이지요. R로 전환하려면 R로 바꿔서 더 좋은 분석결과가 나왔다를 증명해야 하는 선행프로젝트를 아마도 하게 될텐데 대부분 차이점이 별로 안 나옵니다. 이런 경우 비용절감외에는 프로젝트 성공 요건을 맞추기가 어렵습니다.

비용문제가 있어도 SAS를 써야합니다. 어차피 SAS의 대부분의 기능중 아주 일부만 사용하는 경우가 대부분이며 생각보다 많은 라이센스가 필요하지 않습니다. 라이센스를 줄이면 됩니다. (잘 살펴보세요. DB툴과  Excel로도 할 수 있는 것이 대부분인 경우도 많습니다) 그리고 R을 사용하겠다고 실무자가 진행한다고 해도 어차피 보장해 줄 제조사가 유명회사가 아니면 결정권자가 선택하지도 않습니다.  워런티가 안되지 않습니까. 좀 더 솔직하게 말씀드리면 제 경험으로 볼 때 아이러니하게도 중소기업보다도 R을 사용할 수 있는 환경적 기반이 안되는 회사가 대부분입니다.

R을 사용해야 하는 이유

위의 커뮤니티글에서는 가격이니 버그이니 이런말이 많지만 사실 그보다는 더 결정적인 이유가 있다고 생각합니다. R언어가 알파벳 R을 사용한 이유중 하나로 Research가 있습니다. 연구쪽에서 발전시켜왔고 그쪽 특화된 면이 없지 않습니다.그래서 그런지 R은 최신 알고리즘, 모형, 방법론, 연구논문에 대한 실제 코드 등이 매우 빠른 속도로 제공되고 계속해서 업데이트 됩니다.  이런 패키지와 문서의 분량이 너무 방대해서 감당할 수 없을 정도입니다.  IT관련 패키지들이 아닌 모형, 분석 방법론, 알고리즘, 실험에 대한 자료들 얘기입니다.

R – 콜택시/대리운전 데이터 분석 예제 #1

콜택시/대리운전 데이터 분석 예제 #1

SKT의 빅데이터허브에서 받은 콜택시/대리운전 데이터를 이용한 간단한 Data Munging과 EDA를 위한 전처리의 예제입니다.

들어가기 앞서서…

Data Munging(데이터 먼징)은 데이터를 분석하기 위해 데이터를 여러 형태로 변환하는 것을 말합니다. (Data Wrangling 이라고도 합니다) ETL이 뭔지 아신다면 간단한 형태의 on-demand ETL이라고 생각하면 됩니다. Data Munging을 시스템을 이용해서 자동화하면 ETL이 됩니다.

EDA는 다들 알다시피 탐색적데이터분석(Exploratory Data Analysis)입니다. 최근의 추세는 EDA를 위해서 전처리와 Data Munging에서 EDA까지 한꺼번에 수행하는 것이 많습니다. (유행…)

해보기…

우선 bigdatahub.co.kr에서 콜택시/대리운전 데이터를 다운로드 모두 받습니다. 취향이겠지만 TSV 형식으로 받으면 좋습니다. 탭으로 구분된 것이 콤머로 구분된 것보다 다루기 편합니다.

CSV형식은 따옴표의 escaping등의 문제가 늘 있으므로 가끔 이런것이 문제를 일으킵니다. 이런 문제를 미연에 방지하기 위해 TSV형식을 사용하는 것이 좋습니다.
단, 당연한 것이지만 데이터 내부에는 Tab이 들어 있지 않다는 전제가 필요합니다.

TSV형식은 Tab Seprated View의 약어로 구분자(delimiter)가 tab 문자로 구분된 형식입니다. 이 예제에서 파일들이 저장된 경로는 다음과 같습니다. (제 PC는 Mac입니다)

각자의 경로에 맞게 잘 수정하시기 바랍니다.

#!!{"brush":"r"}
filepath <- "/Users/euriion/Downloads/skt_datahub/seoul_calltaxi/"

저장된 파일 목록을 살펴봅니다.

#!!{"brush":"r"}
system(paste("cd", filepath, "; ", "ls -1 *.tsv")) 

이제 파일이름들로 된 character 타입 벡터를 하나 만들어 줍니다. copy & paste를 하시던가 타이핑을 열심히 하던가 해야 합니다.

#!!{"brush":"r"}
filenames <- c(
"서울지역+콜택시+대리운전+이용분석_2013년+8월.tsv",
"서울_콜택시_대리운전이용분석_201309.tsv",
"서울_콜택시_대리운전이용분석_201310.tsv",
"서울_콜택시_대리운전이용분석_201311.tsv",
"서울_콜택시_대리운전이용분석_201312.tsv",
"서울_콜택시_대리운전이용분석_201401.tsv",
"서울_콜택시_대리운전이용분석_201402.tsv"
)

다른 tsv파일들이 들어있지 않다면 타이핑하지 않고 그냥 불러올 수 있습니다.

오타방지와 노동력 낭비 방지를 위해서도 이 방법이 더 낫습니다. system 펑션에 intern 옵션을 True로 해주면 됩니다.

위의 내용을 보실 때 한글 자모가 분리된 형태로 보일 수 있는데 제 작업PC가 Mac OS X라서 그렇습니다. 실제로는 문제는 없습니다.

이제 읽어들일 파일이 헤더가 포함되었는지와 모든 헤더들이 동일한지 간단히 확인합니다. 만약 헤더가 일치하지 않으면 data.frame을 머지(merge)할 때 곤란해집니다. 편의를 위해서 unix 명령을 사용할 것이고 Mac OS X나 Linux를 사용하고 있다면 바로 쓸 수 있습니다.

R을 windows를 사용하고 있다면 msys나 cygwin등을 설치하거나 수작업으로 하는 방법이 있습니다.

#!!{"brush":"r"}
system(paste("cd", filepath, "; ", "ls -1 *.tsv | xargs -n 1 head -1 | sort | uniq -c"))

결과를 보면 한 개의 파일이 다른 헤더를 가지고 있음을 알 수 있습니다.

아마도 “서울지역+콜택시+대리운전+이용분석_2013년+8월.tsv”라는 파일이름을 가진 파일이 원흉일 것입니다. 여튼 header들이 일치하지 않는데 결국 header를 고쳐주거나 header를 무시하고 읽어온 뒤에 header를 다시 붙여주는 방법을 사용해야 합니다. 그리고 어차피 컬럼명이 한글이므로 header는포기하는 것이 유리합니다.

우리는 header를 포기하고 column name들은 임의로 붙일 것입니다. 자 이제 여러 tsv 파일을 모두 읽어서 하나의 data.frame으로 만들어야 합니다.

그래야 다루기 쉽습니다.

파일들을 일곱번 읽어서 rbind하는 방법등 여러가지 방법이 있습니다. 그리고 그 외에도 방법은 여러가지가 있습니다만 여기서는 작업의 편의를 위해서 plyr를 이용해서 한 번에 읽어 버리도록 하겠습니다. plyr 패키지를 불러옵니다. 설치가 되어 있지 않다면 당연히 설치를 해 주어야 합니다.

plyr 설치하기

#!!{"brush":"r"}
if (!require(plyr)) { 
    install.packages("plyr") 
}

이제 paste0를 이용해 파일 이름들의 fullpath 벡터를 만들어줍니다.

#!!{"brush":"r"} 
filenames.fullpath <- paste0(filepath, filenames) 
filenames.fullpath

아래는 결과입니다.

#!!{"brush":"r"}
## [1] "/Users/euriion/Downloads/skt_datahub/seoul_calltaxi/서울_콜택시_대리운전이용분석_201309.tsv" 
## [2] "/Users/euriion/Downloads/skt_datahub/seoul_calltaxi/서울_콜택시_대리운전이용분석_201310.tsv" 
## [3] "/Users/euriion/Downloads/skt_datahub/seoul_calltaxi/서울_콜택시_대리운전이용분석_201311.tsv" 
## [4] "/Users/euriion/Downloads/skt_datahub/seoul_calltaxi/서울_콜택시_대리운전이용분석_201312.tsv" 
## [5] "/Users/euriion/Downloads/skt_datahub/seoul_calltaxi/서울_콜택시_대리운전이용분석_201401.tsv" 
## [6] "/Users/euriion/Downloads/skt_datahub/seoul_calltaxi/서울_콜택시_대리운전이용분석_201402.tsv" 
## [7] "/Users/euriion/Downloads/skt_datahub/seoul_calltaxi/서울지역+콜택시+대리운전+이용분석_2013년+8월.tsv" 

파일 이름이 절대경로로 잘 붙어 있는 것을 확인할 수 있습니다. 자 이제 ldply를 이용해서 몽땅 불러옵니다. header를 읽지 않기 위해서 skip=1 옵션을 준 것을 주의하세요.

#!!{"brush":"r"}
df <- read.table(filename, , sep = "t", header = F, skip = 1)))

자 파일을 읽어 왔습니다. 내용을 확인해 봅니다.

#!!{"brush":"r"}
head(df)

확인해보니 ldply를 사용하면서column이 하나 더 붙었습니다만 그것은 나중에 확인하기로 하고 우선 레코드를 빼먹지 않고 모두 data.frame으로 읽어 왔는지 확인해 봅니다.

#!!{"brush":"r"}
NROW(df)

총 3115 개의 레코드가 읽혔는데 맞는지 확인해 봅니다. unix명령어의 wc를 이용해서 확인합니다.

#!!{"brush":"r"}
system(paste("cd", filepath, "; ", "wc -l *.tsv"))

3122개가 나왔는데 header의 개수 7을 빼면 3115가 맞습니다. (산수! 산수!)

자 이제 컬럼명을 바꿔줍니다. 원래 컬럼명은 아래와 같습니다.

#!!{"brush":"r"}
colnames(df)

아래는 결과입니다.

#!!{"brush":"r"}
"Filename" "V1" "V2" "V3" "V4" "V5"

컬럼명을 안 바꾸고 그냥 써도 되겠지만 컬럼의 의미를 인식하기 어려우므로 바꿔줍니다. (깔맞춤의 미학)

그전에 보면 맨 앞의 컬럼명이 filename인데 이것은 하등 쓸모가 없으므로 먼저 제거합니다.

#!!{"brush":"r"}
df <- df[,2:6]

컬럼이름을 바꿔줍니다.

#!!{"brush":"r"}
colnames(df) <- c("yearmon", "sido", "gugun", "dong", "freq")

컬럼이름이 로마자 병음 방식으로 상당히 무식해 보이지만 체신청(우체국)과 안행부에서도 채택(?)하고 있는 전통적으로 많이 쓰는 예술적인 네이밍룰입니다.

컬럼이 잘 바뀌었는지 확인해 봅니다.

#!!{"brush":"r"}
head(df)

아래는 결과입니다.

#!!{"brush":"r"}
yearmon sido gugun dong freq
1 201309 서울특별시 강남구 압구정동 5
2 201309 서울특별시 강남구 일원2동 8
3 201309 서울특별시 강남구 대치3동 39
4 201309 서울특별시 강남구 일원동 55
5 201309 서울특별시 강남구 압구정1동 82
6 201309 서울특별시 강남구 대치1동 87

다 되었습니다. 여기까지 데이터를 읽어오는 과정이었습니다. 기회가 되면 이 데이터를 가지고 EDA인 Descriptive Statistics를 해보겠습니다.

R ARIMA 예제 코드

R의 ARIMA 모형의 예제입니다.
서버의 메모리의 사용량의 추이를 보고 얼마 후에 고갈되는지를 예측하는 코드입니다.
물론 예측력은 많이 떨어지고 현실성이 없을 수 있습니다.

# -------------------------
# Memory usage forecasting
# -------------------------
library(stats)
arima(lh, order = c(1,0,0))
arima(lh, order = c(3,0,0))
arima(lh, order = c(1,0,1))

arima(lh, order = c(3,0,0), method = "CSS")

arima(USAccDeaths, order = c(0,1,1), seasonal = list(order=c(0,1,1)))
arima(USAccDeaths, order = c(0,1,1), seasonal = list(order=c(0,1,1)),
method = "CSS") # drops first 13 observations.
# for a model with as few years as this, we want full ML

arima(LakeHuron, order = c(2,0,0), xreg = time(LakeHuron)-1920)

## presidents contains NAs
## graphs in example(acf) suggest order 1 or 3
require(graphics)
(fit1 <- arima(presidents, c(1, 0, 0)))
tsdiag(fit1)
(fit3 <- arima(presidents, c(3, 0, 0))) # smaller AIC
tsdiag(fit3)

# ----- prediction part

od <- options(digits=5) # avoid too much spurious accuracy
predict(arima(lh, order = c(3,0,0)), n.ahead = 12)

(fit <- arima(USAccDeaths, order = c(0,1,1),
seasonal = list(order=c(0,1,1))))
predict(fit, n.ahead = 6)
options(od)

# ----- Arima
library(forecast)
fit <- Arima(WWWusage,c(3,1,0))
plot(forecast(fit))

x <- fracdiff.sim( 100, ma = -.4, d = .3)$series
fit <- arfima(x)
plot(forecast(fit,h=30))

# ----- Arima forecast for memory usage (unit %) -----
library(forecast) # need to install the package "forecast"
memory.usage.threshold <- 100 # 100%
memory.usage.forecast.period <- 30 # 미래 30일분까지 예측
memory.usage.observations.startdate <- "2012-09-01"
memory.usage.observations <- c(10,11,30,35,36,39,48,56,75,69,68,72,71,72,83) # 관측치 12일분

memory.usage.period <- seq(as.Date(memory.usage.observations.startdate), length=length(memory.usage.observations), by="1 day") # 날짜세팅
memory.usage.df <- data.frame(row.names=memory.usage.period, memory=memory.usage.observations) # data.frame으로 변환
memory.usage.ts <- ts(data=memory.usage.df) # time series 생성
memory.usage.model <- auto.arima(memory.usage.ts) # arima 모델 생성
memory.usage.forecast <- forecast(memory.usage.model, h=memory.usage.forecast.period) # forecast 결과 생성
memory.usage.forecast.df <- as.data.frame(memory.usage.forecast) # forecast 결과 변환

d = memory.usage.threshold,][1,])) # 100 이 넘는 최초 데이터 추출
if(is.na(d)) {
print(sprintf("앞으로 %s일동안 %s%% 초과하지 않음", memory.usage.forecast.period, d - length(memory.usage.observations)))
} else {
print(sprintf("%s일 후에 %s%% 초과됨", d - length(memory.usage.observations), memory.usage.threshold))
}

# ---- 시각화(Plotting)
plot(memory.usage.forecast) # plotting
abline(h=100, col = "red", lty=3)
abline(v=d, col = "red", lty=3)

library(ggplot2)
library(scales)

plt <- ggplot(data=pd,aes(x=date,y=observed))
p1a<-p1a+geom_line(col='red')
p1a<-p1a+geom_line(aes(y=fitted),col='blue')
p1a<-p1a+geom_line(aes(y=forecast))+geom_ribbon(aes(ymin=lo95,ymax=hi95),alpha=.25)
p1a<-p1a+scale_x_date(name='',breaks='1 year',minor_breaks='1 month',labels=date_format("%b-%y"),expand=c(0,0))
p1a<-p1a+scale_y_continuous(name='Units of Y')
p1a<-p1a+opts(axis.text.x=theme_text(size=10),title='Arima Fit to Simulated Datan (black=forecast, blue=fitted, red=data, shadow=95% conf. interval)')

원본 소스코드는 아래에 있습니다.

https://github.com/euriion/code_snippets/blob/master/R/forecast_exam.R

R ggplot2 – 경제인구동향 그래프 찍기

R에서 ggplot2경제활동인구찍기를 해봤습니다.
사실은 다른 것을 플로팅해보려다가 원하는 자료를 다운로드 받는 것이 만만치 않아서
대충 지나가다가 통계청 데이터중에 처음 보는 것을 가지고 찍어본 것입니다.
우선은 데이터를 가져와야 합니다. 통계청에 가시면 여러가지 통계데이터를 제공하고 있습니다.
아래 사이트에 가서 경제활동인구동향데이터를 긁어 옵니다.
http://kosis.kr/feature/feature_0103List.jsp?mode=getList&menuId=03&NUM=180

CSV로 다운로드 받아서 해도 되겠지만 데이터가 크지 않으므로 그냥 소스코드에 집어넣기 위해서 copy&paste를 해버립니다.
사이트에서 바로 복사하면 컬럼간의 구분이 Tab으로 되어 있을텐데요.
편집기에서 제가 Tab문자를 쓰지 않아서 Tab을 모두 세미콜론(;)으로 바꿨습니다. 그리고 header를 month와 population으로 해서 column 이름을 아예 데이터에서 지정해버렸습니다.

코드는 아래와 같습니다.
economic_activity_population <- "month;population
2009.09;24,630
2009.10;24,655
2009.11;24,625
2009.12;24,063
2010.01;24,082
2010.02;24,035
2010.03;24,382
2010.04;24,858
2010.05;25,099
2010.06;25,158
2010.07;25,232
2010.08;24,836
2010.09;24,911
2010.10;25,004
2010.11;24,847
2010.12;24,538
2011.01;24,114
2011.02;24,431
2011.03;24,918
2011.04;25,240
2011.05;25,480
2011.06;25,592
2011.07;25,473
2011.08;25,257
2011.09;25,076
2011.10;25,409
2011.11;25,318
2011.12;24,880
2012.01;24,585
2012.02;24,825
2012.03;25,210
2012.04;25,653
2012.05;25,939
2012.06;25,939
2012.07;25,901
2012.08;25,623"

자 이제 data.frame으로 로딩합니다.

statdata <- read.table(file=textConnection(econonic_activity_population), header = TRUE, sep = ";", quote = ""'", as.is=TRUE,colClasses=c("character", "character"))

그리고 나서
statdata$month 컬럼을 Date형식으로 바꿔줍니다. 그러지 않으면 나중에 곤란해집니다. 궁금하시면 직접해 보시구요.
년도와 날짜로만 되어 있는 문자열을 날짜형으로 바꾸기 위해서 강제로 01을 붙여서 그달의 첫째날로 바꿔버립니다.
그리고 바꿀때 타임존(tz)을 서울(Asia/Seoul)로 해줍니다. 안해주면 가끔 날짜가 UTC로 바뀌는 경우가 있습니다.


statdata$month <- as.Date(paste(statdata$month, ".01", sep=""), "%Y.%m.%d", tz="Asia/Seoul")

그리고 statdata$population을 숫자형으로 바꿔줍니다. 그런데 숫자데이터에 콤머가 있으므로 콤머를 다 제거해주고 숫자형으로 바꿉니다.

코드는 아래와 같습니다.

statdata$population <- as.numeric(gsub(",", "", statdata$population))

자 이제 플로팅을 해보죠. ggplot2를 로딩한 다음에 바로 찍습니다. ggplot2를 설치하지 않으셨으면 먼저 설치하셔야 합니다.

install.packages("ggplot2") # 설치를 안했으면 먼저 설치부터...

library(ggplot2) # 로딩
ggplot(statdata, aes(x=month, y=population)) + geom_line()

플로팅한 그림은 아래와 같습니다.

나왔네요. 그런데 회색배경에 검은선이라 이쁘지 않네요.
선에 색을 넣어 봅니다.

ggplot(statdata, aes(x=month, y=population)) + geom_line(colour="blue")

조금 낫긴하지만 역시 허전합니다.
아래가 비어서 그런것 같으니 선을 그리지 말고 채우기를 이용해서 그려보죠.
사실 이런류의 데이터는 색을 채우지 않고 선으로 보는 것이 데이터를 보기에는 더 좋습니다만 누군가에게 던져 줄때는 예쁘게 출력하는 것도 중요합니다.
본인이 보는 그래프는 선으로 된 것이면 충분하지만 누군가에게 보여주는 그래프는 알록달록해야 합니다.


gplot(statdata, aes(x=month, y=population)) + geom_area()

찍었습니다. 그런데 어라? 그래프의 모양이 바뀐것 같습니다. 자세히 보니 Y축이 영역(range)가 바뀐것 같은데 그것 때문에 밋밋해진 것이군요.
geom_area는 기본적으로 Y축의 0값부터 채워 넣기 때문에 geom_line과는 다르게 반응합니다.
그래서 Y축의 레인지를 강제로 고쳐줘야 합니다. 밑부분의 넙다란 부분을 잘라서 없애버리는 것입니다.


ggplot(statdata, aes(x=month, y=population)) + geom_area() + coord_cartesian(ylim = c(23500, 26500))

그럴듯하게 나오네요. 그런데 여전히 색이 단조롭네요.
테두리의 선색과 채울때 쓴 색을 다르게 줘서 입체감을 조금 살려보죠. 조금 옅은 회색과 조금 진한 회색을 써보겠습니다.


ggplot(statdata, aes(x=month, y=population)) + geom_area(colour="gray10", fill="gray50") + coord_cartesian(ylim = c(23500, 26500))

조금 괜찮아졌습니다만 역시 흑백보다는 칼라를 넣는 것이 좋을 것 같네요.
삷이 우울해질것만 같습니다.
제가 좋아하는 보라색을 넣어봅니다.

ggplot(statdata, aes(x=month, y=population)) + geom_area(colour="gray10", fill="gray50") + coord_cartesian(ylim = c(23500, 26500))

유후~ 괜찮아졌네요.
자. 이제 대충 색은 되었고 나머지를 조금 더 손을 봐보죠.
Y축의 값은 단위를 천명으로 한 숫자입니다. 통계청 데이터의 설명에 그렇게 나와 있습니다.
원래 숫자대로 바꿔보죠. 값에 곱하기 1000을 해서 원래 숫자로 바꿉니다.
귀찮으니 이쯤에서 처음부터 데이터를 다시 로딩해서 바꿔버립니다. 기존 데이터에 그냥해도 무방합니다.

statdata <- read.table(file=textConnection(econonic_activity_population), header = TRUE, sep = ";", quote = ""'", as.is=TRUE,colClasses=c("character", "character"))

statdata$month <- as.Date(paste(statdata$month, ".01", sep=""), "%Y.%m.%d", tz="Asia/Seoul")
statdata$population <- as.numeric(gsub(",", "", statdata$population)) * 1000

네 바꿨습니다. Y축 레인지를 조절하는 값도 1000을 곱해서 바꿔줘야 하는것을 기억하시구요.
이제 Y축의 레이블값의 숫자들에게 콤머를 찍어줍니다. 콤머를 찍으려면 scales 패키지를 로딩해야 합니다.

library(scales)
ggplot(statdata, aes(x=month, y=population)) + geom_area(colour="#5c0ab9", fill="#8a4fcd") + coord_cartesian(ylim = c(23500000, 26500000)) + scale_y_continuous(labels=comma)

이제 X축의 레이블들을 수정해봅니다. 2011-01 처럼 되어 있는 것을 2011년 011월 이렇게 바꿔줄 것입니다.
한글 폰트를 지정해 주시는 것을 잊지 말아야 합니다.. 저는 맥을 사용하므로 애플산돌고딕네오를 적었습니다만 Windows 사용자라면 “맑은 고딕”같은 것을 사용해주세요. 폰트를 정확히 지정하지 않으면 한글이 출력되지 않습니다.


ggplot(statdata, aes(x=month, y=population)) + geom_area(colour="#5c0ab9", fill="#8a4fcd") + coord_cartesian(ylim = c(23500000, 26500000)) + scale_y_continuous(labels=comma) + scale_x_date(labels = date_format("%Y년 %m월")) + theme(axis.text.x = element_text(family="Apple SD Gothic Neo"))

자! 되었습니다.
이제 마지막으로 X축과 Y축의 타이틀을 한글로 바꿔줍니다.
month와  population을 년/월과 경제활동인구라는 말로 바꿔줄 것입니다.
그러면서 코드를 좀 깔끔하게 정리해 보죠. 한줄에 너무 덕지덕지 다 붙여 놓으면 나중에 찾아서 고치기가 어렵습니다.


ggp <- ggplot(statdata, aes(x=month, y=population))
ggp <- ggp + geom_area(colour="#5c0ab9", fill="#8a4fcd")
ggp <- ggp + coord_cartesian(ylim = c(23500000, 26500000))
ggp <- ggp + scale_y_continuous(labels=comma)
ggp <- ggp + scale_x_date(labels = date_format("%Y년 %m월"))
ggp <- ggp + xlab("년도/월") + ylab("경제활동인구")
theme.title <- element_text(family="Apple SD Gothic Neo", face="bold", size=12, angle=00, hjust=0.54, vjust=0.5)
theme.text <- element_text(family="Apple SD Gothic Neo", size=10)
ggp <- ggp + theme(axis.title.x = theme.title, axis.title.y = theme.title, axis.text.x = theme.text)
ggp
rm(theme.title)
rm(theme.text)
gc()

드디어 완성입니다.
아주 이쁘지는 않지만 그럭저럭 보여줄만한 수준이 되는 것 같습니다.

다음 포스트에서는 플롯의 영역별로 색을 지정하는 것을 해보죠.