gimmesilver's blog

Agbird.egloos.com

포토로그



word2vec으로 게임 아이템 의미 벡터 추출하기 데이터분석

0. Introduction 

  word2vec 알고리즘은 이름에서 알 수 있듯이 단어를 벡터 형태로 변환해 주는 알고리즘입니다. 데이터 분석을 할 때 가장 중요한 것 중 하나는 내가 모델링하고자 하는 대상을 적절한 수치형 자료(벡터나 스칼라)로 표현하는 것입니다. 이것을 보통 feature engineering 이라고 하는데 대상이 갖고 있는 특징들을 최대한 뽑아내는 동시에 노이즈는 잘 제거하는 것이 핵심입니다.
  기존에는 데이터 분석가 및 도메인 전문가가 다양한 탐사 분석을 통해 적절한 특질(feature)들을 뽑아내고 이 중에서 내가 모델링하고자 하는 목적에 가장 잘 부합하는 특질들만을 선별하기 위해 step-wise 나 regularization 등의 기법을 사용하는 것이 일반적인 접근 방법이었습니다. 그러나 최근에 딥러닝 기법들이 발전하면서 feature engineering 역시 뉴럴 네트워크 기반의 다양한 알고리즘을 이용해 자동화되고 있습니다. 대표적으로 Autoencoder가 있으며 최근에는 Convoluional Neural Network(CNN)가 이미지 인식 분야에서 활발하게 사용되고 있습니다. 오늘 소개하는 word2vec 역시 자연어 처리 분야에서 많은 관심을 받고 있는 뉴럴 네트워크 기반의 feature engineering 알고리즘입니다.
  word2vec에 대해서는 이미 인터넷에 다양한 소개글이 있기 때문에 별도로 소개할 필요는 없을 것 같습니다. 혹시 이 알고리즘에 대해 잘 모르시는 분은 http://www.moreagile.net/2014/11/word2vec.html 을 참고하시기 바랍니다.
  word2vec은 원래 자연어 처리를 목적으로 만들어지긴 했으나 이론적으로는 텍스트와 유사한 특성을 가진 데이터라면 어떤 것이든 word2vec 알고리즘을 이용할 수 있습니다. 최규민님이 쓰신 https://brunch.co.kr/@goodvc78/16 에서는 아프리카 TV 에서 시청자의 시청 이력을 이용해 컨텐츠를 추천하는데 활용하는 사례를 소개하고 있습니다.
  저는 최규민님이 소개하신 아이디어를 참고하여 각 유저별로 게임 내에 있는 상점에서 구매한 아이템 이력 데이터에 word2vec을 적용했을 때 게임 아이템의 의미(특질) 벡터를 잘 생성하는지 테스트한 내용을 간략히 소개하고자 합니다.

1. 아이템 구매 이력에 word2vec 적용하기

  분석에 사용한 게임은 엔씨소프트의 모바일 게임인 '리니지 레드나이츠(이하 RK)' 입니다. RK는 리니지 IP를 이용한 수집형 RPG 게임입니다. 상점을 통해 다양한 장비나 소환수 영혼석, 장비 제작 및 소환수 육성을 위한 재료들을 구입할 수 있어서 유저별 다양한 구매 이력 데이터를 추출할 수 있습니다.

혹시 안해보신 분들은 한번 다운로드 받아서 해보시길...^^;

  아래 그림은 파이썬 노트북에서 word2vec으로 게임 아이템 의미 벡터를 추출하는 코드입니다. 사전에 게임 로그로부터 추출한 각 유저별 구매 아이템 목록을 pandas 의 데이터 프레임으로 불러온 후(1) 데이터를 확인해 보면 (2)와 같이 유저별로 구매한 아이템이 한 줄에 나열된 것을 볼 수 있습니다. 각각의 구매 이력에서 아이템은 콤마(,)로 구분되어 있는데 이것을 다시 배열로 변환(3)한 후 (4)와 같이 wod2vec 알고리즘을 이용해 벡터 모델을 생성합니다(여기서 size는 벡터의 차원을 의미합니다). 참고로 word2vec 알고리즘을 사용할 때는 토픽 모델링용 라이브러리인 gensim(https://radimrehurek.com/gensim/) 을 이용했습니다.


  (5)에서는 각 아이템의 의미 벡터가 잘 생성되었는지 확인해 보기 위해 '2월 스페셜 패키지' 라는 상품 아이템에 대한 의미 벡터를 화면에 출력해 보았습니다. 비록 이 벡터의 각 원소값이 의미하는 바를 정확히 이해할 수 없습니다만, 충분히 많은 데이터로 학습을 했다면 적어도 이 벡터는 같이 구매한 경향이 높은 아이템끼리는 유사도가 높도록 벡터가 구성될 것입니다.
  예를 들어 (6)을 보면 '아델하이드 영혼석'이라는 아이템과 유사도가 높은 아이템 목록이 나열되어 있습니다(각 아이템의 옆에 있는 숫자는 '아델하이드 영혼석'과의 코사인 유사도입니다). 즉, '아델하이드 영혼석'을 구매하는 유저는 '커츠 영혼석'도 같이 구매하는 경향이 가장 높다는 뜻이죠. 실제 이 게임을 해보신 분은 아시겠지만 '아델하이드'는 마법 공격 방어용 소환수이고 '커츠'는 물리 공격 방어용 소환수인데 보통 게임 유저들은 이 둘을 같이 키우는 경향이 높기 때문에 둘의 구매 유사도가 가장 높게 나오는 것은 직관적으로도 납득할 수 있는 결과입니다.

2. 아이템 의미 벡터로 추론 관계 연산하기

  뭐니뭐니해도 word2vec 을 가장 유명하게 만든 것은 벡터 연산을 통해 대상 간의 의미 관계를 추론하는 것입니다. 예를 들어 아래와 같이 'king', 'queen', 'man', 'woman' 이라는 네 개의 단어에 대한 의미 벡터가 있다면,
이것을 이용해서 'king' - 'man' + 'woman' = 'queen' 이라는 연산을 할 수 있죠.
  다시 말해 '왕' 이라는 단어에서 '남자'라는 의미를 뺀 후, 대신 '여자'라는 의미를 더하면 '여왕'이라는 단어가 나오는 것입니다. 물론 위 예는 매우 이상적인 예이며 실제로는 직관과 잘 맞지 않는 사례도 많긴 하지만, (충분히 많은 데이터와 차원을 적용하면) 굳이 언어 전문가가 일일이 각 단어에 대한 의미 규칙을 구성하지 않더라도 인간과 유사한 추론이 가능한 벡터를 만들 수 있다는 것이 word2vec 의 가장 흥미로운 점입니다.

  그런데 구매 이력을 이용해 추출한 게임 아이템의 의미 벡터 역시 위와 비슷한 연산이 가능합니다. 아래 코드는 소환수 영혼석에 대한 벡터 연산 예입니다.

  위 코드 및 결과를 벡터 연산으로 표기하면 '에스텔 영혼석' - '아델하이드 영혼석' + '제니스 퀸 영혼석' = '좀비로드 영혼석' 입니다. 다시 말해 위 네 소환수에 대한 벡터 연산을 앞서 예로 든 'king', 'man', 'queen', 'woman' 에 대한 벡터 연산에 매칭해서 보면 아래 그림과 같습니다.
  이 결과를 이해하려면 각 소환수의 특성에 대한 설명이 필요한데요, 먼저 '에스텔' 이라는 소환수는 '인간형 마법 딜러'이며 '아델하이드'는 '인간형 마법 탱커'입니다.
에스텔(인간형 마법딜러)

아델하이드(인간형 마법탱커)

  한편 좀비로드와 제니스퀸은 전투에서의 역할이 각각 '마법딜러'와 '마법탱커' 이기 때문에 이런 역할 측면에서 보면 각각 에스텔과 아델하이드에 매칭이 됩니다. 또한 이 두 소환수는 '비인간형' 소환수(정확하게는 하나는 '마족형'이고 다른 하나는 '야수형')라는 점에서 공통점이 있습니다. (아래 그림을 보면 뭔가 외모에서 풍기는 분위기가 비슷하죠? ^^)
좀비로드(마족형 마법딜러)

제니스 퀸(야수형 마법탱커)

  결국 실제 각 소환수의 특성을 분석가가 일일이 지정하지 않더라도 단지 구매 이력만을 이용해 word2vec 알고리즘을 적용했더니 각 소환수의 속성(딜러형, 탱커형, 인간형, 비인간형)을 의미적으로 해석할 수 있는 벡터를 생성할 수 있었으며 이를 통해 '인간형 마법 딜러'에서 '인간형 마법 탱커'를 빼고 여기에 '비인간형 마법 탱커'를 넣었더니 '비인간형 마법 딜러'가 나오는 추론 연산을 할 수 있었던 것이죠.

실제 이렇게 계산되는 것은 아니지만 이해를 돕기 위해 그림으로 표현한 예

3. 의미 벡터 클러스터링을 통한 아이템 카테고리 생성하기

  마지막으로 구매 이력을 통해 얻을 수 있는 모든 아이템들의 의미 벡터가 실제 우리가 직관적으로 이해하고 있는 아이템 속성 카테고리와 얼마나 유사한지 비교해 보기 위해 클러스터링을 해 보았습니다. 이 작업은 R에서 했는데, 보기 편하도록 먼저 PCA를 이용해 전체 12차원 벡터를 2차원 벡터로 축소한 후 DBSCAN이라는 알고리즘을 사용해서 클러스터링을 수행했습니다. 사용한 코드 및 결과는 아래와 같습니다.

library(dbscan)
library(ggplot2)
library(ggrepel) # 플롯에서 라벨이 서로 겹쳐서 보이지 않도록 재조정하는 라이브러리

# 각 아이템별 벡터 데이터 불러오기
data <- read.csv('item2vec.csv')

# 차원 축소를 위해 PCA 이용
vec.pca <- prcomp(data)
item2vec <- data.frame(item=data$item, vec.pca$x[, 1:2])

# DBCAN 클러스터링 알고리즘 이용
set.seed(1234)
item.cluster <- dbscan(item2vec[, c('PC1', 'PC2')], eps=1)
item2vec$cluster <- as.factor(item.cluster$cluster)

# 클러스터링 결과 시각화
my.theme <- theme_bw() + theme(text = element_text(size=14, face='bold'))
ggplot(item2vec, aes(x=PC1, y=PC2, col=cluster)) + geom_point() + my.theme + geom_text_repel(aes(label=item, col=cluster), size=3)

  그림을 확대해서 자세히 보면 비교적 의미적으로 비슷한 아이템들끼리 군집이 잘 형성되는 것을 볼 수 있습니다. 예를 들어 초보 영웅들을 위한 장비류가 같이 묶이거나(왼쪽의 초록색 그룹) 소환수 연성에 활용하는 재료 중 '순수한 XXX 비약' 아이템들끼리 묶이거나(왼쪽에서 두번째 연두색 그룹) 소환수 영혼석들이 같은 클러스터에 묶이기도 하죠(오른쪽 노란색 그룹). 만약 차원 축소를 하지 않고 클러스터링에 더 신경을 쓴다면 더 정교한 카테고리 분류가 가능할 것 같습니다.

4. 결론

  요즘 뉴럴 네트워크 기반의 feature engineering 알고리즘이 많은 인기를 끌고 있습니다. 이 중에서 word2vec은 자연어 처리를 위해 만들어진 알고리즘이지만 높은 성능을 갖고 있으면서 처리 속도 역시 빨라 자연어 처리 뿐만 아니라 다른 분야에서도 이 알고리즘을 적용하기 위한 다양한 시도를 하고 있습니다. 저도 일종의 컨셉 검증 차원에서 게임 아이템 구매 내역을 이용해서 게임 아이템의 의미 벡터를 추출하는 매우 간단한 실험을 해봤는데 예상보다 훨씬 더 아이템의 의미 벡터를 잘 생성하는 것 같습니다.
  그럼 이렇게 만든 의미 벡터는 어떻게 활용할 수 있을까요? 아직 이 부분에 대해서는 명확히 생각을 정리하지 못했습니다. 최규민님의 글에서는 벡터간 유사도를 이용해 추천 엔진에 활용하는 아이디어를 제시하고 있지만 실제 유용한 수준으로 구현하려면 이것만으로는 많이 부족할 것이라 생각합니다. 특히 제가 사용한 게임의 경우 각 유저가 구매할 수 있는 상점 아이템 목록이 매우 제한적이기 때문에 구매 유사도 기반의 추천 방식은 적절하지 않습니다.
  다만 이렇게 정성적인 데이터를 비교적 직관적으로 볼 때 잘 맞는 수준으로 정량화할 수 있다는 것 자체만으로도 그 가능성은 매우 크다고 생각합니다. 더 나아가 이번에는 단순히 구매 이력만을 이용했지만 그 외에도 다양한 시퀀스 데이터를 적용해 보면 다른 좋은 서비스 적용 방안이 나올 수 있지 않을까 생각합니다.

덧글

댓글 입력 영역