Women’s e-commerce cloting reviews 데이터를 바탕으로 텍스트 데이터를 예측모형에 Feature로 넣어 예측력을 향상시키는 방안을 살펴보자.
현장에서 자연어 처리(NLP)는 매우 드물지만 텍스트 데이터에 대한 중요도는 지속적으로 증대되고 있다. 이를 현재 시점에서 대응하는 한 방식이 깔끔한 데이터(Tidy Data) 원칙을 단순히 단어를 세는 Count-based 방법론과 결합하면 상당히 실무에서 유용하게 활용할 수 있게 된다.
캐글 Women’s e-commerce cloting reviews 데이터는 총 11개 변수로 구성되어 있고 관측점이 23,486개로 구성되어 있다. Recommended IND를 라벨 목표변수로 두고 예측모형을 구축해보자.
캐글 옷 리뷰 데이터에서 텍스트 관련 변수(Title
, Review
)를 따로 빼서 직사각형 데이터프레임을 생성한다. 즉, 텍스트는 별도로 빼서 DTM을 만들어 결합시킨다. 텍스트 Feature를 모형설계행렬로 반영한 후 예측모형 알고리즘을 돌려 예측모형 정확도를 향상시킨다.
cloth_dat <- cloth_dat %>%
clean_names() %>%
filter(complete.cases(.)) %>%
rename(y = recommended_ind)
cloth_df <- cloth_dat %>%
mutate(y = factor(y, levels=c(1,0), labels=c("yes", "no"))) %>%
mutate_if(is.character, as.factor) %>%
select(y, age, title, review_text, division_name, department_name, class_name) %>%
mutate(class = fct_lump(class_name, 9)) %>%
mutate(review = str_c(title, " ", review_text)) %>%
select(y, age, division = division_name, department = department_name, class, review) %>%
mutate(review_id = row_number())
cloth_text_df <- cloth_df %>%
select(review_id, review)
cloth_text_df %>%
sample_n(10) %>%
DT::datatable()
원본 텍스트 데이터를 unnest_tokens()
함수로 깔끔한 텍스트 형태로 변환시킨다. 그리고 나서 불용어 사전에서 불용어를 anti_join()
으로 제거한다.
추천과 비추천에 많이 사용된 단어를 상위 10개 뽑아 비교한다.
cloth_df %>%
select(review_id, y) %>%
left_join(cloth_tidytext_df) %>%
count(word, y, sort=TRUE) %>%
group_by(y) %>%
top_n(10, wt=n) %>%
ungroup() %>%
ggplot(aes(x = fct_reorder(word, n), y=n, fill=y)) +
geom_col() +
coord_flip() +
facet_wrap(~y, scales = "free") +
labs(x="", y="") +
scale_y_continuous(labels = scales::comma)
옷추천과 비추천을 감성분석과 연계하여 추천에 활용된 긍정적인 단어와 비추천에 활용도가 높은 단어 빈도수를 비교한다.
cloth_tidytext_df %>%
inner_join(get_sentiments("bing")) %>%
count(word, sentiment, sort=TRUE) %>%
group_by(sentiment) %>%
top_n(10, wt=n) %>%
ungroup() %>%
ggplot(aes(x=reorder(word,n), y=n, fill=sentiment)) +
geom_col() +
coord_flip() +
facet_wrap(~sentiment, scales = "free") +
labs(x="", y="") +
scale_y_continuous(labels = scales::comma)
리뷰에 나타난 전체를 파악하는 대신에, 추천과 비추천 리뷰에 동원된 감성어도 각기 나눠 살펴볼 수 있다. 이를 위해서 review_id
를 추천여부와 결합하여 감성분석결과와 결합하여 구분필드로 활용한다.
cloth_df %>%
select(review_id, y) %>%
left_join(cloth_tidytext_df) %>%
inner_join(get_sentiments("bing")) %>%
count(y, word, sentiment, sort=TRUE) %>%
group_by(y, sentiment) %>%
top_n(10, wt=n) %>%
ungroup() %>%
ggplot(aes(x=fct_reorder(word, n), y=n, fill=sentiment)) +
geom_col() +
coord_flip() +
facet_wrap(~y+sentiment, scales = "free") +
labs(x="", y="") +
scale_y_continuous(labels = scales::comma)
tf-idf
tf-idf
는 옷리뷰에 대한 추천과 비추천 분석에 대한 중요지표가 된다. bind_tf_idf()
함수로 추천과 비추천 리뷰에 대한 중요단어를 추출하여 막대그래프로 시각화한다.
## 리뷰 전체 단어숫자
review_words <- cloth_tidytext_df %>%
count(review_id, word, sort = TRUE)
total_review_words <- review_words %>%
group_by(review_id) %>%
summarize(total = sum(n))
## 리뷰 TF-IDF
cloth_tidytext_tfidf <- cloth_tidytext_df %>%
count(review_id, word) %>%
left_join(total_review_words) %>%
bind_tf_idf(word, review_id, n)
cloth_tidytext_tfidf %>%
top_n(100, wt=tf_idf) %>%
arrange(desc(tf_idf)) %>%
DT::datatable() %>%
DT::formatRound(c(5:7), digits=3)
cloth_df
에서 추천/비추천 필드(y
)를 결합해서 앞서 계산한 tf_idf
와 결합하여 해당 리뷰에서는 자주 나타나고, 전체 리뷰에는 적게 나타나는 단어를, 추천/비추천과 결합하여 중요한 단어를 식별해 낸다.
ngram
tf-idf
token = "ngrams"
을 활용하여 n = 2
로 지정하여 bigram
두단어 토큰을 생성하고 앞선 unigram
토근을 활용한 것과 동일한 방식으로 리뷰를 분석한다. tf_idf
를 계산하여 추천/비추천에 활용된 bigram
두 단어를 식별해보자.
cloth_tidy_bigram <- cloth_text_df %>%
unnest_tokens(bigram, review, token = "ngrams", n = 2)
cloth_tidy_bigram_filtered <- cloth_tidy_bigram %>%
separate(bigram, c("word1", "word2"), sep=" ") %>%
filter(!word1 %in% stop_words$word,
!word2 %in% stop_words$word) %>%
unite(bigram, word1, word2, sep = " ")
cloth_tidy_ngram_tfidf <- cloth_tidy_bigram_filtered %>%
count(review_id, bigram, sort=TRUE) %>%
bind_tf_idf(bigram, review_id, n)
cloth_tidy_ngram_tfidf
# A tibble: 125,109 x 6
review_id bigram n tf idf tf_idf
<int> <chr> <int> <dbl> <dbl> <dbl>
1 2219 amp amp 11 0.423 7.78 3.29
2 502 bathing suit 5 0.417 5.79 2.41
3 14404 love love 5 0.714 4.27 3.05
4 10884 amp amp 4 0.222 7.78 1.73
5 13346 stain remover 4 0.444 8.25 3.67
6 195 sweater coat 3 0.25 5.93 1.48
7 211 amp 39 3 0.3 7.22 2.17
8 407 amp 39 3 0.429 7.22 3.10
9 520 beach cover 3 0.25 6.68 1.67
10 1205 upper arms 3 0.375 6.06 2.27
# ... with 125,099 more rows
ggraph
)텍스트 데이터에 대한 탐색적 데이터분석과 비지도 학습 모형에 대한 검토가 끝났다면 다음 단계로 옷추천에 대한 예측모형을 구축하는 것이다. 이를 위해서 tidytext
, quanteda
, tidymodels
3가지 도구가 시장에 나와 있다.
library(doSNOW)
library(caret)
# 실행시간
start.time <- Sys.time()
cl <- makeCluster(4, type = "SOCK")
registerDoSNOW(cl)
sparse_words <- cloth_tidytext_df %>%
count(y, review_id, word, sort = TRUE) %>%
cast_sparse(review_id, word, n)
model <- cv.glmnet(sparse_words, cloth_df$y, family = "binomial",
parallel = TRUE, keep = TRUE)
stopCluster(cl)
total.time <- Sys.time() - start.time
total.time