brunch

You can make anything
by writing

C.S.Lewis

by 레오군 Mar 04. 2019

마이리얼트립 여행 후기 데이터 분석

R을 이용한 텍스트 데이터 분석

마이리얼트립에는 45만개가 넘는 여행 후기 데이터가 쌓여 있습니다. 세세한 맥락 정보가 생략될 수 밖에 없는 정량 데이터와는 달리, 텍스트로 남는 여행 후기 데이터는 다녀온 여행에서 구체적으로 어떤 점이 좋았는지(혹은 불편했는지)를 상세히 알려주는 굉장히 소중한 자료입니다. 실제로 여행상품을 예약할 때 사용자들이 가장 많이 참고하는 요소 중 하나이기도 하구요. 마이리얼트립 직원들 역시, 사용자분들이 어떤 경험을 하는지 확인하기 위해서 여행 후 남겨지는 후기들을 꼼꼼하게 살펴보고 있습니다. (특히 1점 후기 ㅠㅜ)


5점을 받은 ‘매우 만족’ 후기와 1점을 받은 ‘매우 불만족’ 후기가 어떻게 다른지, 후기를 남길 때 어떤 단어들을 쓰는지를 살펴보면 사용자들이 좋아할만한 여행 상품을 만드는 데 힌트를 얻을 수 있지 않을까요? ‘만족스러운 여행 경험’에 영향을 미치는 변수들은 무엇일까? 에 대한 아이디어를 얻기 위해서, 마이리얼트립 여행 후기 데이터를 분석해 보았습니다.




분석 대상 데이터셋 가져오기

누적 데이터가 너무 많아서, 일단 2018년 1년 간 쌓인 후기 데이터만 가져와서 분석을 진행하기로 했습니다. (raw_data는 아래와 같은 형태입니다.) 평점을 기준으로 그룹핑하고, 특수문자를 제거하는 것으로 간단한 전처리를 완료했습니다. 

raw data는 이렇게 생겼습니다
# 필요한 패키지 로드
library(tidyverse)
library(KoNLP)
library(reshape2)
library(wordcloud2)
library(tidygraph) 
library(ggraph)

# 데이터 준비
review_2018  #raw data

# 평점 기준으로 그룹핑
score1 <- review_2018 %>% filter(score==1)
score5 <- review_2018 %>% filter(score==5)

# 특수문자를 제거한 텍스트 데이터만 남기기
review_score1 <- str_replace_all(score1$message, "\\W"," ")
review_score5 <- str_replace_all(score5$message, "\\W"," ")


품사 태깅하기

R에서 한글 텍스트분석을 하는 데 가장 널리 사용되는 패키지는 KoNLP 입니다. KoNLP를 로드하면 다양한 함수를 사용해서 문장을 형태소단위로 쪼개고, 적절한 품사 태그를 붙일 수 있습니다. (자세한 내용은 여기를 참조) 

본 분석에서는 KoNLP의 SimplePos09() 함수를 사용하여, 리뷰 내용중에서 체언[N: 명사, 대명사, 수사]과 용언[P: 동사, 형용사, 보조용언]에 해당하는 단어들을 추출해서 테이블과 워드클라우드를 만들었습니다. 


#### SimplePos09 를 이용한 품사 태깅 ####
# N 체언: 명사, 대명사, 수사
# P 용언: 동사, 형용사, 보조용언 

# 사전을 정의합니다
useSejongDic()

# 품사 태그 붙이기
raw_score5 <- SimplePos09(review_score5) %>% melt() %>% select(3,1)

# 체언(N), 용언(P)에 해당하는 단어 추출
score5_NP <- raw_score5 %>% 
  mutate(extract = str_match(value, '([가-힣]+)/[NP]')[,2]) %>% 
  filter(!is.na(extract))

# 용언(P)의 경우, 어미에 '다'를 붙여서 형용사/동사 형태로 변경
score5_NP$keyword <- ifelse(str_detect(score5_NP$value, "/P"), paste0(score5_NP$extract, '다'), paste(score5_NP$extract))
score5_NP$type <- ifelse(str_detect(score5_NP$value, "/P"), 'P', 'N')

# 상위 100개 추출하여 테이블 만들기 (+추출된 형태소가 2글자 이상인 것만 남김)
score5_NP_table <- score5_NP %>%
  filter(str_length(extract) >= 2) %>% 
  group_by(keyword) %>%
  summarise(cnt = n()) %>%
  arrange(desc(cnt)) %>%
  head(100)

# 워드클라우드 만들기
score5_NP_table %>% 
  wordcloud2(fontFamily='NanumGothic', size = 0.8, color = 'random-dark', minRotation=0,
maxRotation=0)


워드클라우드

평점 5점 후기와, 평점 1점 후기에서 각각 뽑아낸 명사, 대명사, 동사, 형용사 로 만든 워드클라우드는 아래와 같습니다. (상위 100개 추출)

5점 리뷰로 만든 워드클라우드
1점 리뷰로 만든 워드클라우드

몇 가지 재미있는 결과가 보이긴 하는데요. (5점 리뷰에서는 ‘가이드님’이 많고, 1점 리뷰에서는 ‘가이드’가 많다던지??;;) 이 경우 ‘여행’, ‘투어’, ‘가이드’ 등 양쪽 결과에 모두 나타나는 중립적인 단어들로 인해 그룹 간 차이를 명확하게 구분하기가 어렵습니다. 그래서 양쪽 그룹에서 모두 100위 안에 든 텍스트를 제외하고, 각 그룹에서 Unique하게 확인되는 텍스트 기준으로 워드클라우드를 다시 만들어 보았습니다.


# 1점 리뷰와 5점 리뷰 각각 상위 100 키워드
score1_NP_keyword <- score1_NP_table %>% select(keyword) %>% unlist()
score5_NP_keyword <- score5_NP_table %>% select(keyword) %>% unlist()

# 1점 리뷰 상위 100위안에 드는 키워드를 제외하고 워드클라우드 다시 그리기
score5_NP_only <- score5_NP %>%
  filter(str_length(extract) >= 2) %>% 
  filter(!(keyword %in% score1_NP_keyword)) %>% 
  group_by(keyword) %>%
  summarise(cnt = n()) %>%
  arrange(desc(cnt)) %>%
  head(100)

score5_NP_only %>% 
  wordcloud2(fontFamily='NanumGothic', size = 0.8, color = 'random-dark', minRotation=0, maxRotation=0)


5점 리뷰에서만 볼 수 있는 단어
1점 리뷰에서만 볼 수 있는 단어

이렇게 보니 5점과 1점을 대표하는 단어가 명확하게 구분됩니다. ‘편하다’와 ‘안되다’가 대표 키워드라고 할 수 있겠네요. 5점 후기의 경우 감정을 표현하는 형용사들이 상대적으로 많은 것을 확인할 수 있습니다. 상대적으로 1점 후기에서는 ‘환불’이나 ‘연락’ 등 불만족의 원인이 되는 명사형 키워드들이 많이 포함된 게 눈에 띕니다. 


텍스트에 포함된 단어의 노출빈도(frequency)를 기반으로 한 워드클라우드를 만드는 것은 전체 데이터를 요약해서 한 눈으로 확인하는 데 매우 효율적인 방법이지만 뚜렷한 단점이 있습니다. 단어와 단어 간 연관성을 알기가 어렵다는 점입니다. 가령, 위 케이스에서는 ‘편하다’와 ‘안되다’를 대표단어로 뽑아낼 수는 있지만 무엇이 편해서 좋았는지, 무엇이 안되서 실망했는지…에 대한 구체적인 내용을 알기가 어렵습니다.




바이그램

단순히 등록된 단어의 빈도를 세는 것 이외에, 단어 간의 관계를 좀 더 자세히 확인할수 있는 방법이 있을까요? 가장 심플한 n-gram 분석방법인 바이그램(Bigram)을 이용하여 추가적인 시각화를 해 보았습니다. (바이그램은 문장에서 사용된 전/후 단어를 2개씩 조합해서 분석하는 것을 의미합니다. 자세한 설명은 여기를 참조)


# 바이그램 테이블 만들기
bigram_score5 <- score5_NP %>% 
  filter(str_length(extract) >= 2) %>% 
  select(keyword) %>% 
  mutate(lead=lead(keyword)) %>% 
  filter(keyword != lead) %>% 
  unite(bigram, c(keyword, lead), sep=' ') %>% 
  count(bigram, sort=TRUE) %>% 
  head(30) %>% 
  separate(bigram, c('word1', 'word2'))

# 바이그램 그래프 그리기
bigram_score5 %>% 
  as_tbl_graph %>% 
  ggraph() + 
  geom_edge_link(aes(start_cap = label_rect(node1.name), end_cap = label_rect(node2.name)), edge_color = 'blue', edge_width = 1) + 
  geom_node_text(aes(label=name), size = 5, color = 'darkblue', fontface = 'bold') +
  theme_classic()


5점 리뷰의 Bigram 그래프


1점 리뷰의 Bigram 그래프


문장의 전/후 단어를 함께 고려함으로써, 위와 같이 맥락이 조금 더 포함된 구체적인 정보를 확인할 수 있게 되었습니다. 5점 후기와 1점 후기에 모두 ‘시간’ 이라는 단어가 사용되었지만, 5점 후기에서는 ‘시간’ 이라는 단어가 ‘즐겁다’ / ‘보내다’ 등과 함께 사용된 반면 1점 후기에서는 ‘기다리다’ / ‘걸리다’ 등과 같은 부정적인 단어와 함께 사용되었네요. 1점 후기에서 가장 두드러지게 나온 ‘안되다’ 와 함께 사용된 단어들은 ‘연락’, ‘충전’, ‘환불’ 과 같은 명사인데요. ‘무엇이 안되어서 불만족했는지’를 훨씬 더 명확하게 알 수 있습니다.


위 케이스에는 전체 데이터를 사용한 예시를 보여드렸지만, 분석에 사용하는 데이터셋을 어떤 식으로 준비하고 전처리하느냐에 따라 엄청나게 다양한 결과를 볼 수 있습니다. 가령, 오사카 상품 리뷰와 로마 상품 리뷰를 비교한다던지, 혼자 다녀온 배낭여행자들의 리뷰와 가족여행으로 다녀온 분들의 리뷰를 비교한다던지 하는 식으로 말이죠. 혹은, 위 케이스에서처럼 다양한 품사를 한꺼번에 뽑아내지 말고 하나씩 집중해서 볼 수도 있겠네요. (예를 들면, ‘명사’만 태깅하기)




이상으로 간단한(?) 한글 텍스트분석에 대해서 알아봤습니다. 사실 한글 텍스트분석의 경우 데이터 전처리가 꽤 번거롭고 시간이 많이 걸리는 작업인데요. (오타가 있는 단어, 띄어쓰기가 되지 않은 문장…의 경우, 형태소로 쪼개거나 품사 태깅하는 과정이 매끄럽게 진행되지 않습니다. 또 표준어가 아닌 구어체를 사용하는 경우에도 문제가 됩니다.  예를 들면 “가이드님 깨알지식 재밌었어요. TMI스럽긴 했지만 ㅋㅋ 갠적으로 완전강추!” 이런 거? -_-) 이 글에서는 전처리를 위한 ‘노가다’에 해당하는 부분은 가능한 간략하게 기술했습니다.  


모든 데이터 분석 과정이 그렇겠지만, 특히나 정성데이터는 분석과정의 자유도가 높아서 분석가의 질문과 상상력이 중요한 것 같습니다. (역시 중요한 건 좋은 질문!) 더불어, 이 글에는 모두 공개되지 않았지만, 텍스트분석 결과를 정리하고 인사이트를 찾아내는 과정에서는 매일같이 1점 후기를 정독(!)하고 계신 마이리얼트립 운영팀 분들의 도움을 많이 받았고 + 앞으로 더 많은 도움을 받을 예정입니다. 


마지막으로,
이렇게 재미있는 데이터가 한가득 쌓여있고, 좋은 사람들이 함께 일하는 곳. 마이리얼트립에서 함께 할 동료들을 찾고 있습니다.

많은 포지션이 열려있고, 아직 늦지 않았어요!


https://career.myrealtrip.com/




브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari