R 3.4.1 릴리즈

2017년 6월 30일자로 R 3.4.1 버전이 릴리즈(release) 되었습니다.

패키지 설치시 문제와 펑션에 유니코드가 포함되어 있을 때 디스플레이에서 발생하는 문제를 비롯한 패키지 개발관련의 버그들이 수정되었다고 합니다.

3.4.1의 코드네임은 “Single Candle”입니다. 3.4.0의 코드네임은 “You stupid darkness” 이더군요. R은 늘 코드네임을 이해가 쉽게 안가는 것을 붙이는데 이번에는 코드네임이 왜 이런가 하고 링크를 봤더니 아래의 “피너츠”(찰리브라운과 스누피?) 만화의 대사이더군요.

전 귀찮아서 아직 업그레이드를 안했습니다만…

 

Hive server 2에 python impyla 패키지로 접속하기

ipyhton 또는 그냥 python script로 Hive에 접속해서 SQL을 실행하고 결과 데이터를 가져오게 하려면 굉장히 고통스럽습니다.

Python에서 사용할 수 있는 Hive 접속관련 패키지들이 상당히 불안하고 버그가 많습니다. 다 해결해주는 깔끔한 끝판왕이 하나 나와줬으면 싶은데 Hive가 일반 RDBMS 처럼 쓰는 것은 아니어서 그런지 아직까지 깔끔하게 해결해 주는 패키지가 없습니다.

Hive 자체에서 제공하는 python client라는 것이 있긴한데 이걸 쓰려고하면 설정을 위해서 상당히 귀찮은 작업들을 해야 합니다.  예전에 했을 때는 되긴했었습니다만 다시하고 싶지 않습니다.

배보다 배꼽이커요.

그런데
Cloudera에서 impala용 client를 만들어서 제공하는데 이 패키지가 impala 뿐만 아니라 HiveServer2에 접속하는 기능도 제공합니다.
이것 말고도 HiveServer2에 접속할 수 있게 해주는 Python 패키지중에 pyhs2라는 것이 있는데 이 패키지도 동일한 기능을 제공하지만 더 이상 업데이트 하지 않고 impyla를 사용하라고 github에 pyhs2 제작자가 적어놨더군요.  그 외에도 몇개의 패키지가 있습니다만 모두 불편했습니다.

그래서 현재까지 가장 쉽게 Python에서 Hive에 연결해서 쿼리를 실행하거나 작은 실행 결과를 바로 가져오는 방법은 Python에서 HiveServer2에 접속하게 하고  HiveServer2에 접속하기 위해서  impyla 패키지를 쓰는 것입니다. (다른 더 쉬운 방법이 있으면 알려주세요)

impyla 패키지를 사용하려면 당연히 Hive server 2가 어딘가 네트워크로 접속할 수 있는 서버에서 작동하고 있어야 합니다. 이 패키지는 Hive server 2에 접속하는 것이니까요.

그냥 Hive하고 Hive server 2가 다른 것이라는 것은 아시지요? Hive server 2는 Hive를 별도로 Daemon으로 띄워서 사용하게 해주는 일종의 add-on 입니다. Hive에 같이 포함되어 있으니 설정을 잡아주고 구동만 시키면 됩니다.

그런데 이 impyla 패키지도 의존성으로 가진 Thrift 관련된 패키지가 여러단계로 조금씩 의존성이 꼬여 있어서 설치할 때 조금 귀찮게 합니다. 그래서 impyla 패키지를 설치할 때 조금 고생하게 되는데 그때 필요한 것들을 정리도 할겸 포스트로 올립니다.

CentOS Linux에서는 다음과 같은 문제를 고려해서 설치하면 현재는 작동이 됩니다.  각 환경마다 사정이 다르기 때문에 모두 동일하게 해결된다는 보장은 없습니다. Ubuntu에서는 안해봤습니다.

Ubuntu에서도 잘 될 것이라고 생각합니다.

impyla 관련 패키지 설치하기

우선 python package이름이 impala가 아니고 impyla 인것에 주의하시구요. 패키지 이름이 “임팔라”가 아니고 “임파일라”입니다. 무척 헷갈립니다. 게다가 python 코드 내에서 import 할때는 impala를 호출해야 합니다. (왜 그랬는지…)

설치할 때 주의해야 할 중요한  내용입니다.

  • Thrift에 접속할 때 인증을 위해서 sasl 관련 library가 필요합니다.  CentOS에서는 yum으로 검색해서 cyrus로 시작하는 sasl 패키지들을 설치해 주어야 합니다. 특히 cyrus-sasl-plain을 설치해야 Hive Server 2에 plain 방식으로  id/password를 입력하고 접속할 수 있습니다. 현재는 Hive Server 2 plain 방식이 아니면 접속할 수 없었습니다. cyrus sasl의 기본 설치에서 제외되므로  빼먹지 말고 찾아서 설치해야 합니다.
  • impyla 패키지가 thrift 패키지에 의존성을 가지는데 현재 0.9.3 이하가 아니면 작동하지 않도록 되어 있습니다. 나중에는 고쳐질 수 있겠습니다만 지금은 아닙니다.  thrift의 현재 시점에서의 최신 버전은 0.10.0 입니다. 그래서 이미 0.10.0 버전으로 설치되어 있으면 0.9.3 이하로 downgrade해야합니다.
  • 기타 thrift 패키지 설치에 필요한 의존성 패키지가 있습니다만 환경에 따라 이미 설치가 되어 있을 수도 있습니다. 의존성 오류가 발생하면 그 패키지를 설치하면 됩니다. 이 것들은 대충 막 설치해도 큰 충돌은 없는 것들입니다.
  • impyla 패키지가 pypi에 등록된 것은 위와 같이 해도 trans관련 오류를 내면서 제대로 접속하지 못합니다. 즉 pip 같은 것으로 빌드된 것을 설치하면 안될 수 있습니다. 그래서 impyla를 설치할 때는 소스를 clone받아서 빌드하고 설치해야 합니다.
  • 이때 thrift_sasl 패키지도 설치해 주어야 thrift를 통한 인증과 암호화 문제를 해결할 수 있습니다.

제가 작업하는 환경에서 작업한 shell command를 정리한 것입니다. python 2.7 버전 기준입니다. 3.x 도 되었던 것 같습니다만 기억이 가물가물하네요.

# install sasl releative packages and thrift
sudo yum install cyrus-sasl.x86_64 cyrus-sasl-devel.x86_64 cyrus-sasl-gssapi.x86_64 cyrus-sasl-md5.x86_64 cyrus-sasl-plain.x86_64 cyrus-sasl-ntlm.x86_64 cyrus-sasl-sql.x86_64 python-saslwrapper.x86_64 libgsasl-devel.x86_64 -y
sudo pip2.7 install thrift_sasl
sudo pip2.7 uninstall thrift  # 0.9.3 version is necessary. so 0.10.0 should be uninstalled
sudo pip2.7 install 'bitarray'
sudo pip2.7 install 'thrift<=0.9.3'

# sudo pip2.7 install pyhs2  # deprecated
# pip install git+https://github.com/cloudera/impyla.git

# install impyla. pypi impyla has a bug. so install from source
mkdir ~/__setup
cd ~/__setup
git clone https://github.com/cloudera/impyla.git
cd impyla
sudo python2.7 setup.py install
cd -
# sudo rm -Rf ~/__setup

이렇게 설치하고 나서 간단하게 작동하는지 다음과 같이 테스트해 보면됩니다. 서버주소와 ID, password, query는 환경에 맞게 수정하셔야 합니다. 당연한 것이지만 아래의 코드는 그대로 실행하면 접속을 못해서 에러입니다.

from impala.dbapi import connect

conn = connect(host='hive-server-2.aidenhong.com',
               port=10000,
               user='hiveuser',
               password='hivepassword',
               auth_mechanism='PLAIN')

cursor = conn.cursor()
cursor.get_databases()  # database 목록 가져오기

cursor.execute("select * from aiden.iris limit 10")  #  query 실행하기 예제
results = cursor.fetchall()
for row in results:
    print row

impyla 패키지의 github 레파지토리는 다음과 같습니다.

https://github.com/cloudera/impyla

향 후 패키지가 업데이트 되고 더 안정화되면 위의 자질구레한 문제들이 자동으로 해결될 수도 있을지도 모릅니다. 그런데 Cloudera 사람들이 저 패키지에 신경을 별로 안쓰는 것 같아서 조금 걱정은 됩니다.

타임라인 광고 타겟팅 – timeline ad targeting

 

지금 하는 일과 관련이 있는 것이라서 zdnet기사에 앱넥스트라는 회사에서 제안했다고 하는 타임라인 타겟팅이라는 기법(아이디어)에 대한 기사를 스크랩해 놓은적이 있는데 내용도 정리할겸 그림툴도 써볼겸(사실은 이게 본래의 포스팅 목적입니다 ‘ㅡ’;;) 해서 포스트를 올립니다.

직접 기사를 읽어보시면 되겠지만 저는 그림툴을 사용해 보는 것이 목적이므로 정리를 좀 해보자면 이렇습니다.

최근의 앱인스톨 광고 그러니까 앱인스톨을 유도하는 배너 광고들이 실적이 좋지 않다고 합니다.  그 이유 중의 하나가 이제 사람들은 자기 스마트폰에 더 이상 새로운 앱을 설치하지 않는다고 합니다.

  1. 이미 필요한 것을 대부분 설치했고 사용하는 것들이 몇개에 한정되어 있기 때문입니다.
  2. 그리고 필요한 것이 생기면 그때그때 찾아서 설치해도 되니 미리 설치해 둘 필요는 없습니다.
  3. 게임이 아니라면 그런 배너에 반응을 잘 안하게 되는 게임도 설치 광고가 그렇게 큰 효과를 보지 못한다는 말이 많습니다. (다 그런것은 아니겠지만요)

그래서 위 기사에서 말하는 아이디어는 이렇습니다.

일종의 개인화 타겟팅(personalized targeting)인데 위의 그림처럼 사람들의 타임라인을 추적(감시한다기 보다는 엿본다는 것이 맞겠습니다)해서 상황들을 모니터링하다가 특정 상황이 되면 그 상황에 필요한 앱인데 아직 사용자가 설치하지 않은 앱이 있다면 광고로 추천해서 바로 설치하도록 유도한다는 것입니다.

그러기 위해서 사용자가 사용하고 있는 스마트폰에 항상 사용자의 액션을 모니터링하는 앱이 필요한데 사실 대부분의 회사들이 이걸 하기가 현실적으로 불가능합니다. 스마트폰의 모든 상황을 전역으로 감시하는 장치를 스마트폰에 심을 수가 없기 때문입니다.

앱넥스트라는 회사는 자사의 SDK(스마트폰 애플리케이션에 광고를 노출할 수 있도록 해주는 킷)를 사용한 제휴 앱들을 이용해서 사용자의 행적(activity)를 보고 있다가 다른 앱을 설치하도록 유도할 수 있다는 것입니다. 알려주는 것은 아마 Push 기능 같은 것을 사용하지 않을까 싶습니다.

실현이 가능하다면 “앱을 설치할 수 밖에 없는 적절한 상황을 찾아서 그때 광고를 보여주면 설치를 많이 하겠지” 라는 것을 이용한 것인데요.

이걸 하기 위해서는 사실 앱 매체(광고를 보여주는 앱들)을 많이 제휴하고 있어서 그 앱들을 사용자가 늘 쓰고 있거나 빈번하게 쓰고 있어야 합니다. 즉 앱 매체 커버리지가 좋아야 합니다. 이것은 사실 진입장벽이 매우 높아서 말이 후발주자(모바일 광고 플랫폼 회사)들이 제휴한 앱들이 많지 않으면 힘듭니다. 아니면 끝판왕 하나를 제휴하던지요(카카오톡 같은 것?)

위의 앱 매체 제약 조건이 걸린다면 일반적인 PC 온라인 광고에서는 응용할 수 있는 방법은 라이프타임에 대한 모니터링을 길게 해서 상품을 추천해 주는 방법을 얼른 생각해도 할 수 있을것만 같습니다.

어떤 온라인 사용자가 추정 모델 또는 데이터온보딩(data on-boarding)으로 20대 여성이라는 것을 알고 다음과 같은 순서로 제품에 관심을 보였거나 구매를 했다면 그 다음 상황에 필요한 것을 유추해서 추천해 줄 수 있습니다.

청바지 → 워킹용 신발 → 워터프루프 화장품 → 수영복 → 카메라방수팩

다소 억지로 만든 예입니다만 저런 시퀀스가 있다면 카메라방수팩을 광고해서 구매하도록 유도할 수 있습니다.  물론 이것도 앱매체의 커버리지 문제처럼 온라인 웹페이지와 제휴가 많이 되어 있어야 하고 제품도 골고루 보여줘서 어떤 행동(behavior)를 하는지 시차를 두고 기록해 둬야 하는 문제가 있습니다. 물론 광고에 잘 반응하는 사람일 수록 하기 쉽고 그렇지 않은 사람이나 특정 쇼핑몰(G마켓 이랄지)에서만 구매를 하는 사람들이라면 조금 어렵습니다.

이런 사람들에게는 다 포기하고 조건을 만족하는 사람들에게만 해도 충분할 것 같은 느낌입니다.

필요한 상품의 세트나 연관상품의 세트는 데이터만 있다면 노출이나 클릭, 구매 기록으로부터 연관 규칙 탐사(sequence association rule mining)같은 간단한 방법으로도 정보를 추출해서 확보 할 수도 있을 것 같은데  실제로 해보지는 않았지만 간단한 시뮬레이션 정도는 해볼 수 있을 것 같습니다.

다시 앱의 문제로 돌아와서 만약 카카오톡 같은 사람들이 매우 많이 쓰는 앱이라면 사용자의 메세지 텍스트를 분석해서 (윤리적으로 그러면 안되는 것은 당연하고) 문맥을 파악한 뒤 필요한 것을 알아내서 카톡내에서 광고를 보여주고 추천해 주는 방법도 고민해 볼 수 있겠습니다. (그냥 상상입니다. 현실적으로 안되겠지요)

 

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의 내부구조를 많이 이해한 것이 됩니다.