[R] 6. Topic modeling
반응형
## [1] "ko_KR.UTF-8"
6. Topic modeling
- 토픽 모델링은 클러스터링처럼 텍스트 데이터를 대상으로하는 비지도학습 분류 방법입니다.
- 여러 토픽 모델들이 있는데 그 중 널리 사용되는 LDA(Latent Dirichlet Allocation)에 대해서 살펴보겠습니다.
- 사전에 필요한 라이브러리는
topicmodels
라이브러리로 LDA 객체를 다루는 방법에 대해 소개하겠습니다.
library(topicmodels)
6. 1. Latent Dirichlet Allocation
- LDA는 토픽 모델링을 위한 가장 일반적인 알고리즘 중 하나입니다.
- 해당 포스팅에서는 모델의 수학적인 전개는 생략하고 아래 두 가지 원칙에 대해서만 정리하겠습니다.
- 모든 문서는 토픽이 혼합되어 있다.
- 각 문서가 특정 비율로 여러 토픽의 단어를 포함할 수 있다고 가정
- 예를 들어, 문서 1은 토픽A 90%, 토픽B 10%이고 문서 2는 토픽A 30%, 토픽B 70%
- 모든 토픽은 단어가 혼합되어 있다.
- 예를 들어 하나의 토픽은 “정치”이고 또 다른 하나는 “엔터테인먼트”라고 가정했을 때
- “정치” 토픽에서 많이 사용되는 단어는 “대통령”, “국회”, “정부” 일 수 있으며
“엔터테인먼트” 토픽에서는 “영화”, “TV”, “배우” 등이 될 수도 있다. - 중요한 것은 토픽 간에 단어를 공유할 수 있다는 점
- “예산”과 같은 단어는 두 토픽에 동등하게 나타날 수 있다.
- LDA는 위 두 가지 가정을 기반으로 추정하는 수학적인 방법입니다.
- 지도학습에서의 선형판별분석 LDA(Linear Discriminant Analysis)와 약자가 동일하니 해석 때 주의하셔야 합니다.
- 각 토픽과 관련된 단어의 조합을 찾는 동시에 각 문서를 설명하는 토픽의 조합을 결정합니다.
- 모든 문서는 토픽이 혼합되어 있다.
- 예시를 위해
DocumentTermMatrix
객체인AssociatedPress
데이터를 사용하겠습니다.- 1988년쯤 발행된 미국 통신사의 2,246개 뉴스 기사 모음
data("AssociatedPress")
AssociatedPress
## <<DocumentTermMatrix (documents: 2246, terms: 10473)>>
## Non-/sparse entries: 302031/23220327
## Sparsity : 99%
## Maximal term length: 18
## Weighting : term frequency (tf)
- 적용하는 함수는
topicmodels
라이브러리 함수인LDA()
입니다.
# k는 분류하고자 하는 토픽의 갯수
ap_lda <- LDA(AssociatedPress, k = 2, control = list(seed = 20210720))
ap_lda
## A LDA_VEM topic model with 2 topics.
6. 1. 1. Word-topic probabilities
- 모델에서 \(\beta\) 라고 불리우는 단어-토픽 확률을 구하기 위해서
tidy()
함수를 적용합니다.
ap_topics <- ap_lda %>%
tidy(matrix = "beta")
ap_topics
## # A tibble: 20,946 x 3
## topic term beta
## <int> <chr> <dbl>
## 1 1 aaron 3.31e- 5
## 2 2 aaron 6.71e- 6
## 3 1 abandon 3.23e- 5
## 4 2 abandon 3.77e- 5
## 5 1 abandoned 1.11e- 4
## 6 2 abandoned 6.05e- 5
## 7 1 abandoning 2.24e- 5
## 8 2 abandoning 3.16e-16
## 9 1 abbott 9.99e- 7
## 10 2 abbott 4.61e- 5
## # … with 20,936 more rows
- 그 결과 모델이 토픽(topic) 당 단어(term) 당 하나의 확률(beta)값을 갖는 데이터 형태가 되었습니다.
- 해석을 하자면, 해당 토픽에서 해당 단어가 나올 확률은 beta가 되는 것 입니다.
- 예를 들어 “aaron” 이라는 단어는 토픽1에서 생성될 확률과 토픽2에서의 확률이 서로 다릅니다.
slice_max()
함수를 사용하여 각 토픽에서 일반적인 단어를 캐치할 수 있습니다.
ap_top10_terms <- ap_topics %>%
group_by(topic) %>%
slice_max(beta, n = 10) %>%
ungroup() %>%
arrange(topic, desc(beta))
ap_top10_terms
## # A tibble: 20 x 3
## topic term beta
## <int> <chr> <dbl>
## 1 1 i 0.00716
## 2 1 people 0.00504
## 3 1 two 0.00445
## 4 1 president 0.00426
## 5 1 police 0.00404
## 6 1 government 0.00402
## 7 1 soviet 0.00364
## 8 1 bush 0.00343
## 9 1 new 0.00338
## 10 1 years 0.00323
## 11 2 percent 0.0108
## 12 2 million 0.00767
## 13 2 new 0.00661
## 14 2 year 0.00647
## 15 2 billion 0.00507
## 16 2 last 0.00404
## 17 2 company 0.00369
## 18 2 market 0.00358
## 19 2 federal 0.00345
## 20 2 years 0.00284
ap_top10_terms %>%
ggplot(aes(x = reorder_within(term, beta, within = topic), y = beta, fill = factor(topic))) +
geom_col(show.legend = FALSE) +
facet_wrap(~ topic, scales = "free") +
coord_flip() +
scale_x_reordered()
- 위 결과를 통해 두 가지 주제에 대해서 대략적인 감을 찾아볼 수 있습니다.
- 토픽1은 “people”, “president”, “police”, “government” 등 정치와 관련된 뉴스 기사임을 대략적으로 알 수 있으며
토픽2는 “percent”, “million”, “company”등 경제 관련 뉴스 기사임을 확인할 수 있습니다. - 또한 공통적으로 “years”와 같이 하나의 단어가 두 개의 토픽(클러스터)에서 높은 확률 값을 나타내고 있습니다.
- 이는 기존에 우리가 익숙히 알고 있는 하드한 클러스터링과 다르게 소프트하게 클러스터링을 해볼 수 있다는 장점도 있다는 점을 알려줍니다.
- 다음으로는 두 토픽 간의 가장 큰 차이를 보이는 항을 고려할 수 있습니다.
- 이 차이를 계산하는 방법은 A 대비 B의 방식과 같이 로그비(log-ratio)를 고려합니다.
ap_topics_wider <- ap_topics %>%
mutate(topic = paste0("topic", topic)) %>%
pivot_wider(
names_from = "topic",
values_from = beta,
values_fill = 0
) %>%
filter(topic1 > 0.001 | topic2 > 0.001) %>%
mutate(log_ratio = log2(topic2/topic1))
ap_topics_wider
## # A tibble: 209 x 4
## term topic1 topic2 log_ratio
## <chr> <dbl> <dbl> <dbl>
## 1 administration 1.13e- 3 0.000767 -0.562
## 2 agreement 6.29e- 4 0.00130 1.05
## 3 aid 1.01e- 3 0.0000431 -4.54
## 4 air 8.71e- 4 0.00134 0.628
## 5 american 1.67e- 3 0.00207 0.309
## 6 analysts 2.37e- 6 0.00116 8.94
## 7 army 1.17e- 3 0.0000110 -6.74
## 8 asked 1.41e- 3 0.000327 -2.11
## 9 authorities 1.11e- 3 0.000138 -3.01
## 10 average 7.39e-12 0.00144 27.5
## # … with 199 more rows
ap_topics_wider %>%
group_by(group = ifelse(log_ratio >= 0, "+", "-")) %>%
slice_max(abs(log_ratio), n = 10) %>%
ungroup() %>%
ggplot(aes(x = reorder(term, log_ratio), y = log_ratio)) +
geom_bar(stat = "identity", width = 0.8) +
coord_flip() +
labs(x = NULL, y = "Log2 ratio of beta in topic2 / topic1")
- 위 결과를 통해 확인해볼 수 있는 것은 토픽2는 “stock”, “dollar” 등의 단어와 같이 상대적으로 경제 관련 기사임을 확인해볼 수 있습니다.
6. 1. 2. Document-topic probabilities
- 모델에서 \(\gamma\) 라고 불리우는 문서-토픽 확률을 구하기 위해서 마찬가지로
tidy()
함수를 적용합니다.
ap_documents <- ap_lda %>%
tidy(matrix = "gamma")
ap_documents
## # A tibble: 4,492 x 3
## document topic gamma
## <int> <int> <dbl>
## 1 1 1 0.999
## 2 2 1 0.612
## 3 3 1 0.959
## 4 4 1 0.797
## 5 5 1 0.997
## 6 6 1 1.00
## 7 7 1 0.193
## 8 8 1 0.997
## 9 9 1 0.0261
## 10 10 1 0.926
## # … with 4,482 more rows
- 그 결과 모델이 문서(document) 당 토픽(topic) 당 하나의 확률(gamma)값을 갖는 데이터 형태가 되었습니다.
- 해석을 하자면, 해당 문서에서 해당 토픽에 대한 단어의 추청 확률이 gamma가 되는 것 입니다.
- 예를 들어 문서2에 있는 단어의 약 61%만이 토픽1에서 생성된 것으로 추정합니다. (두번째 줄)
- 위 결과로 보면 문서6은 토픽1에 있는 단어의 거의 100%를 가져왔습니다.
- 따라서 해당 문서에서 가장 빈도가 높은 단어들이 어떤 것인지 확인해볼 수 있습니다.
AssociatedPress %>%
tidy() %>%
filter(document == 6) %>%
arrange(desc(count))
## # A tibble: 287 x 3
## document term count
## <int> <chr> <dbl>
## 1 6 noriega 16
## 2 6 panama 12
## 3 6 jackson 6
## 4 6 powell 6
## 5 6 administration 5
## 6 6 economic 5
## 7 6 general 5
## 8 6 i 5
## 9 6 panamanian 5
## 10 6 american 4
## # … with 277 more rows
6. 2. Example: the great library heist
- 해당 예시를 똑같이 따라해보려고 했는데… 이상하게 파일을 불러올 수가 없네요 ㅠㅠ
- 원인을 확인해보고 확인되는대로 다시 재업로드 하겠습니다.
- 꼭 아래 링크를 통해서 한번쯤은 따라해보고 공부해보시길 권장드립니다. 꼭!
- 필요하신 분들은 여기를 참고해주시면 되어요!
반응형
'tidytext' 카테고리의 다른 글
[R] 5. Converting to and from non-tidy formats (0) | 2021.07.19 |
---|---|
[R] 4. Relationships between words: n-grams and correlations (0) | 2021.07.18 |
[R] 3. Analyzing word and document frequency: TF-IDF (0) | 2021.07.18 |
[R] 한글 형태소 분석 (0) | 2021.07.17 |
[R] unnest_tokens() (0) | 2021.07.17 |
TAGS.