1 왜 워드 임베딩인가?1

1.1 King - Man + Woman = ?

먼저 워드 임베딩(Word Embedding)의 가장 유명한 예제를 구현해보자. 어떻게 해서 300차원 워드 임베딩 모형을 갖게 되면 다음 연산이 가능하다.

library(tidyverse)
library(textdata)

glove6b <- embedding_glove6b(dimensions = 100)

king <- glove6b %>% 
  filter(token == "king") %>% 
  unlist() %>% 
  as.numeric()

man <- glove6b %>% 
  filter(token == "man") %>% 
  unlist() %>% 
  as.numeric()

woman <- glove6b %>% 
  filter(token == "woman") %>% 
  unlist() %>% 
  as.numeric()

what_vector <- king - man + woman
what_matrix <- as.matrix(what_vector[2:101], nrow=1)

glove_mat <- glove6b %>% 
  data.matrix()

glove_mat <- glove_mat[, 2:101]

result_vec <-  glove_mat %*% what_matrix %>% 
  as.vector(.)

what_df <- tibble(token = glove6b$token, similarity = result_vec)

what_df %>% 
  arrange(desc(similarity)) %>% 
  top_n(10, wt=similarity) %>% 
  slice(2) %>% 
  pull(token)
[1] "queen"

상기 결과를 일반화할 수 있는 즉, King - Man + Woman 관계를 단어를 치환해서 계산하는 함수를 작성해서 살펴보자. 관련된 다양한 관계에 대한 내용은 다음 블로그를 참조한다.

get_analogy <- function(king, man, woman) {
  
  king <- glove6b %>% filter(token == king) %>% unlist() %>% as.numeric()
  man <- glove6b %>% filter(token == man) %>% unlist() %>% as.numeric()
  woman <- glove6b %>% filter(token == woman) %>% unlist() %>% as.numeric()
  
  question_vec <- king - man + woman
  question_mat <- as.matrix(question_vec[2:101], nrow=1)
  
  glove_mat <- glove6b %>% 
    data.matrix() %>% 
    .[, 2:101]
  
  answer_vec <-  glove_mat %*% question_mat %>% 
    as.vector(.)
  
  answer_df <- tibble(token = glove6b$token, similarity = answer_vec)
  
  answer_df %>% 
    arrange(desc(similarity)) %>% 
    top_n(6, wt=similarity)
}

get_analogy("king", "man", "woman")
# A tibble: 6 x 2
  token    similarity
  <chr>         <dbl>
1 king           33.2
2 queen          29.9
3 emperor        27.3
4 daughter       26.5
5 throne         25.8
6 princess       25.4
get_analogy("big", "bigger", "small")
# A tibble: 6 x 2
  token similarity
  <chr>      <dbl>
1 small       37.7
2 large       35.3
3 big         32.0
4 a           31.5
5 an          31.1
6 -           31.0
get_analogy("uncle", "man", "woman")
# A tibble: 6 x 2
  token    similarity
  <chr>         <dbl>
1 daughter       28.0
2 wife           26.7
3 mother         26.5
4 married        24.8
5 father         24.4
6 son            23.6

1.2 더 강력한 워드 임베딩

2075.9 MB 크기를 갖는 GloVe 워드 임베딩 모델을 다운로드 받아 압축을 풀면 4095 MB 크기가 된다. embedding_glove840b() 함수를 통해 dir="data" 디렉토리에 저장한다. 1.6백만 단어가 있는 데이터프레임으로 결과가 반환된다.

glove840b <- embedding_glove840b(dir="data")

dim(glove840b)
# [1] 1669210     301

get_analogy <- function(king, man, woman) {
  
  king <- glove840b %>% filter(token == king) %>% unlist() %>% as.numeric()
  man <- glove840b %>% filter(token == man) %>% unlist() %>% as.numeric()
  woman <- glove840b %>% filter(token == woman) %>% unlist() %>% as.numeric()
  
  question_vec <- king - man + woman
  question_mat <- as.matrix(question_vec[2:301], nrow=1)
  
  glove_mat <- glove840b %>% 
    data.matrix() %>% 
    .[, 2:301]
  
  answer_vec <-  glove_mat %*% question_mat %>% 
    as.vector(.)
  
  answer_df <- tibble(token = glove840b$token, similarity = answer_vec)
  
  answer_df %>% 
    arrange(desc(similarity)) %>% 
    top_n(6, wt=similarity)
}

get_analogy("king", "man", "woman")
get_analogy("big", "bigger", "small")
get_analogy("uncle", "man", "woman")
 

데이터 과학자 이광춘 저작

kwangchun.lee.7@gmail.com