• Home

꽤 오랜 시간이 걸릴 R 코드를 돌린다면…

어느정도 R을 사용해본 사람은 알텐데, R언어는 스레드를 제공하지 않는다. 이 때문에 쉘에서의 작업은 대부분 동기적(sync) 방식으로 동작한다. 이 때문에 발생하는 문제는 바로 시간이 오래 걸리는 작업이 실행될 경우인데, 필자의 경우 R쉘에서 Hadoop관련 잡을 돌리기도 하고 데이터베이스와 연동해 쿼리를 실행하기도 해 이런 작업이 실행될 때 기다리거나 다른 주제의 일을 하곤한다.

하나의 분석 작업을 하기 위해 다양한 툴을 사용할 수 있기에 크게 고민하지 않고 이런 한계를 돌파할 생각을 하지 않았는데, 한 팀분이 이 문제에 대해서 효과적인 방법이 없냐고 문의를 해와 고민을 하게 되었고 좋은 방법을 찾아서 공유하는 바이다.

R에서 parallel패키지가 추가된게 약 2년 정도 되었는데, 개인적으로 멀티노드에서의 분산 처리가 가능하게 한 snow통합은 몇번의 시행착오 끝에 사용하지 않기로 마음먹은지 오래다. 뭐 이를 설명하자면 길어지니 다음 기회에 설명할 수 있도록 해보고….

정답을 이야기 하자면 .. parallel패키지에서 제공하는 mcparallel()함수를 사용하면 가능하다. 이 함수의 동작방식은 프로세스 fork기반으로 동작하고 현재 수행되는 R프로세스의 객체를 모두 공유하는(사실은 copy-on-write 방식) 자식 프로세스를 생성해 이 자식에게 잡을 할당하는 것이다. 따라서 이 기능은 윈도우 계열의 OS에서는 동작하지 않으며 분석 머신으로 맥이나 리눅스를 사용하는걸 추천하는 많은 이유중에 하나가 된다.

따라서 결국 코드는 아래와 같은 방식이 될 것이다.

library(parallel)

sleep_time <- 10

p <- mcparallel({
    # do some work
    Sys.sleep(sleep_time)
    iris
}, "get_iris", mc.interactive = TRUE)

# 프로세싱이 완료된 결과를 받아온다.
iris_df <- mccollect(p, wait = F, timeout = sleep_time + 1)[[1]]

위 코드에서 문제는 mccollect로 언제 프로세싱 결과물을 받아와야 되는가인데, wait=TRUE로 주면 위와 같은 코드로 잡을 수행하는 의미가 없다는 문제가 있으니 잡이 모두 수행이 되었을 때 뭔가로 알람을 주면 될 것이다.

예전에 필자의 경우 라즈베리 파이로 센서놀이를 할때 센서의 이벤트를 폰으로 받아보려 pushover라는 앱을 구매한 적이 있는데, 이 앱을 통해서 알람을 받으면 될 거란 생각에 관련 패키지를 찾아보니 notifyR이라는 패키지가 pushover로 메시지를 전송하는 기능을 제공하고 있어 간단하게 아래와 같이 구현해 봤다. 물론 5천원 가량되는 pushover앱을 사용하지 않더라도 이 방식으로도 가능하다.

library(notifyR)
library(parallel)

sleep_time <- 10

p <- mcparallel({
    # do some work
    Sys.sleep(sleep_time)
    # 완료후 메시지 전송
    send_push("user_key.....", message = "잡 종료")
    iris
}, "get_iris", mc.interactive = TRUE)

iris_df <- mccollect(p, wait = F)[[1]]

이상으로 R로 데이터 분석 코드를 실행하고 기다리고 있다는게 변명이 될 수 있다는 사실을 만천하게 공유하는 바이다.

Heartbeat

마지막 블로그 포스팅을 쓴지 한달 반이 지나 뭔가 블로그에 써야될듯 한 그런 사명감때문에 무작정 이렇게 텍스트 에디터를 열었다.

간단하게 최근 현황을 말해본다면 회사 내에서는 맨하튼 프로젝트의 핵폭탄처럼 뭔가 엄청난 왕건이들을 분석하고 만들고 있다는 것과 그 왕건이 중에 큰 애정을 가지고 있는 것이 매우 잘 동작해 흡사 살아있는 생물처럼 느껴진다는 사실 정도라 이야기 해본다. 그 일에 완전 폭 빠져 있어서 블로그든 뭐든 별로 신경을 쓰고 있지않고 있고 특히나 무엇을 시도하기에 최적의 환경을 몇개월동안 구축하고 시행차오를 해와서 이제야 뭔가 실무에서 성과를 점점 보이고 있지 않나 생각해보는데 이런 상황에서 뭔가 소중한 결과를 이끌어내지 못한다면 이는 내 상상력과 노력의 한계라고 밖에 여겨지지 않을 그런 정도의 시간과 환경이라 감히 이야기 해본다. 게다가 무엇보다 팀원과 같이 일하고 생각하고 고민하고 같은 곳을 바라본다는게 얼마나 일을 하는데 큰 성과로 다가오는지 다시한번 느끼는 중이다.

최근에 들어서 거의 24시간을 R쉘에서 생활하고 있는데 얼마전에는 R이 세상에서 갑자기 사라져 직업을 잃어버리는 악몽까지 꿔 R-projects에 소정의 기부까지 하려고 관련 문서 작성까지 마쳤으나 국제펙스를 보내는 고 난이도의 과정에 봉착하고 있는 상황이다. 물론 데이터 크기와 복잡도 때문에 R만을 사용할 수는 없으나 모든 데이터 플랫폼들이 R쉘에 붙게끔 환경 조성을 해놓아서 데이터 프로세싱과 분석의 복잡도에 따라 적절하게 플랫폼을 활용하고 있고 많은 시행착오 끝에 최적의 데이터 핸들링 방법을 나름대로 습득해 잘 분석해 나가고 있다.

개인적인 공부로는 연초에 예측모델링 책을 주로 보다가 최근 두달동안은 아주 작정하고 베이지언에 빠져있다. 주변에서 흔히 이야기 하는 나이브한 베이지언이 아니라 좀더 복잡하고 흥미로운 베이지언인데, 베이지언은 빅 데이터 시대에 아주 잘 맞는 그런 알고리즘 중에 하나라고 확신하고 있는 중이다. 물론 이 알고리즘을 정확하게 적용해 활용하기가 쉽지 않기 때문에 국내 분석 시장에서는 잘 사용되지 않고 있으나 많은 책에 나와 있듯이 정확하게 적용을 하면 최소의 에러를 보장하기 때문에 앞으로 내 인생에서도 많이 활용을 하게 될듯 하다.

이상으로 최근 현황에 대한 공유를 마친다. 그동안 블로그를 안한 대신 팀 세미나를 2월 부터 매주 해오고 있으며 동시에 학교생활도 해야 되서 나름 매우 밀도 있게 사는 중이다. 매우 엑티브하고 재미있게 일한다고 주변에서 조차 느끼고 있다는 피드백이 종종 있는걸 보니 정말 그렇게 사는게 사실인거 같다.

Markdown으로 작성한 문서를 PDF로 변환하기

Markdown문법은 꽤나 편리한 인터페이스를 제공하고 있다고 생각한다. 무엇보다 간단한 문법으로 미려한 문서를 만들 수 있을 뿐 아니라 필요에 따라 여러 기법을 사용할 수 있는 장점을 제공하기 때문이다.

하지만 몇가지 단점중에 하나는 이런 문서를 PDF로 만들기가 꽤나 번거롭다는 것이다. 물론 웹 브라우저를 이용해 PDF로 출력하는게 가능하지만 레이아웃을 HTML을 기반으로부터 변환이 되기 때문에 그다지 좋지 않은 결과물이 나오게 된다.

이런 단점을 보완하는 중요한 툴이 Pandoc이다. 이 툴은 Markdown으로 만들어진 문서를 어떠한 포맷의 문서로든지 변환을 해주는 굉장한 기능을 제공하고 있고, 최근에 knitr와 통합이 되어 편리하게 사용이 가능하다.

문제는 Markdown으로 만들어진 문서를 pdf로 생성하는 것인데, 이를 위해 Latex환경을 갖출 필요가 있다는 것이다. 이 부분에 대해서는 R 시스템에 Latex와 knitr를 통합해 환경을 구성하는 필자의 문서를 참고하기 바란다.

이렇게 준비가 되면 Pandoc 설치문서를 참고해 각 운영체제에 맞게 설정을 해주고 사용은 knitr의 명령어 두가지를 이용해 간단히 만들어 내면 된다.

가장 먼저 아래와 같은 내용의 baysian.op파일을 Markdown파일이 생성될 디렉토리에 함께 넣어준다. 이 파일은 Latex의 헤더에 들어갈 내용이다. 물론 다른 옵션이나 패키지 설정도 해주면 된다.

\usepackage[utf8]{inputenc}
\usepackage[cjk,hangul]{kotex}

그리고 inputs변수와 같은 R Markdown파일을 만들어 준다.

library(knitr)

inputs <- "
<!--pandoc

t: latex
latex-engine: pdflatex
include-in-header: baysian.op
s:

-->

#### 베이지언 룰 

* $p(\\theta|y) =\\dfrac{p(y|\\theta)\\pi(\\theta)}{p(y)}$
  * $p(y)=\\sum\\limits_{i=1}^n p(y|\\theta=i)\\pi(\\theta=i)$

##### 설명 
1. 베이지언 룰은 250년동안 몰래 사용되어 왔다.
"

#R markdown 파일을 markdown파일로 만든다.
knit(text=inputs, output='out.md')
## 
  |                                                                       
  |                                                                 |   0%
  |                                                                       
  |.................................................................| 100%
##   ordinary text without R code
## [1] "out.md"
#pandoc을 이용해 markdown파일을 pdf로 만든다. 
pandoc(input="out.md",format='latex')
## [1] "out.pdf"

이렇게 생성된 문서의 결과는 여기서 확인할 수 있다.

이럴바에야 아래한글이나 MS워드를 쓰는게 낫지 않겠느냐 하겠으나, 필자는 개인적으로 바이너리 포맷의 문서 파일을 좋아하지 않는다. 이유는 모두 나열할 수 없을 정도로 많지만 그중 가장 큰 이유는 문서 이력을 관리하기 힘들다는 것이다. 바이너리 포맷으로는 언제 몇시에 글의 어느 부분을 수정하고 보완했다는 흔적을 남기기가 쉽지 않다는 것이다.