상세 컨텐츠

본문 제목

[Python] tomotopy로 문헌별 토픽 비중 계산하기

프로그래밍/NLP

by ∫2tdt=t²+c 2019. 12. 1. 00:26

본문

이전 글(https://bab2min.tistory.com/633)에서 tomotopy로 간단하게 토픽 모델링을 실시하는 방법에 대해 소개했었는데요, 많은 분들께서 문헌별 주제 비중 계산하는데에 어려움을 겪고 계신듯하여, 문헌별 토픽 비중을 계산하는 방법을 이번 글에서 별도로 소개하도록 하겠습니다. 


먼저 다음과 같이 LDA 토픽 모델을 학습시키도록 하겠습니다.


위 코드를 수행하면 다음과 같이 화면에 출력될 겁니다. 총 3000개의 문헌이 입력되었고, 전체 단어의 개수는 약 400만개네요.

Num docs: 3000

Vocab size: 37020

Num words: 4026898

각각의 입력된 문헌은 add_doc을 수행한 순서대로 차례로 0번부터 2999번까지의 번호를 부여받습니다. 이 번호를 이용해 우리가 원하는 임의의 문서에 접근할 수 있습니다. 한번 첫번째 문헌의 내용을 확인해보도록 합시다.

그럼 이 문헌을 구성하는 토픽의 비율은 어떻게 될까요? 이는 get_topics() 메소드를 통해 확인할 수 있습니다. 다음과 같이 실행해봅시다.

get_topics() 메소드는 top_n이라는 인자를 받습니다. 이는 상위 몇개의 결과를 출력할지 결정합니다. 생략시 자동으로 상위 10개의 결과를 보여줍니다. 결과는 (토픽 번호, 비중)의 리스트로 리턴됩니다. 확인해보니 18번 토픽이 약 61%로 대부분의 내용을 차지하고 있고, 그 다음으로 7번 토픽이 29% 정도를 차지하고 있네요. 나머지 토픽들은 거의 차지하는 비중이 없습니다. 그럼 이 토픽이 0번 문헌의 주요 토픽이라고 볼 수 있겠습니다.

근데 18번 토픽과 7번 토픽이 도대체 뭘까요? 이는 model의 get_topic_words()라는 메소드를 통해서 확인할 수 있습니다. 다음과 같이 실행해봅시다.

get_topic_words() 메소드는 토픽 번호와 top_n 인자를 받아서, 해당 토픽에 포함되는 상위 단어를 보여줍니다. 위 코드에서는 18번 토픽과 7번 토픽의 주요 단어를 10개씩 출력했지요. 내용을 살펴보니 18번 토픽은 생물학과 관련된거 같고, 7번 토픽은 지리와 관련된 거 같습니다. 따라서 0번 문헌은 생물학 관련 내용 61%, 지리 관련 내용 29%를 차지한다고 말할 수 있겠습니다.

우리는 토픽의 개수를 20개로 설정했으므로 3000개 문헌에서 총 20개의 주제를 발견해냈습니다. 그리고 각각의 문헌이 20개의 토픽 중 어떤 토픽을 얼만큼 포함하는지도 확인할 수 있지요. 더 나아가서 각 문헌들의 주요 토픽에 따라 3000개의 문헌을 분류해볼 수도 있겠습니다. 다음 코드는 문헌이 가장 많이 차지하고 있는 토픽에 따라 전체 문헌을 분류해 주는 코드입니다.


위의 코드는 0번부터 19번 토픽에 대해 해당 토픽을 가장 많이 포함한 문헌들을 묶어내줍니다. buckets[7]에는 7번 토픽(위에서 확인한바로는 지리와 관련된 내용이었죠)과 관련된 문헌들이 잔뜩 들어가 있을겁니다. 지리와 관련된 문헌이 몇개나 있는지 그 개수를 살펴볼까요?

7번 토픽을 가장 많이 포함하고 있는 문헌들은 206개라고 하네요. 각각의 문헌 내용을 간단히 살펴봅시다.


... 그렇다고 합니다. 입력으로 사용한 enwiki3000.txt 파일이 이미 stemming이 끝난 상태라 문장을 읽기에는 조금 어려움이 있네요. 전처리 전의 원본 문헌을 같이 저장해두었다가 이때 출력해주면 조금더 알아보기 쉽겠네요. 현재 tomotopy 버전에서는 전처리 전의 문헌과 후의 문헌을 함께 관리하는 기능이 없어서 전처리 결과를 입력으로 넣을 수 밖에 없습니다. 따라서 이 부분은 직접 코드를 짜셔서 각각의 문헌번호에 맞춰 원본 문헌을 보관해주셔야 하겠습니다. 이 역시 좀더 편하게 다룰 수 있도록 인터페이스를 개선할 예정입니다.

급하게 적은 글이라 두서가 없지만, tomotopy 이용에 혼란을 겪고 계신 분들께 도움이 되었으면 좋겠습니다!

관련글 더보기

댓글 영역

  • 프로필 사진
    2019.12.02 17:43
    자세하고 친절한 설명 정말 감사드립니다! 분석하는 데 있어 많은 도움이 되었습니다!!
  • 프로필 사진
    2021.10.26 16:58
    안녕하세요, 제가 두가지 질문이 있어서 댓글 남깁니다!

    1) get_topics(top_n=1)[0][0]
    --> 이부분에서 top_n이 1로 지정되어야 하는 이유와 [0][0] 으로 하는 이유가 궁급합니다.

    2) 그리고 제가 각 토픽별로 제일 비중이 높은 문서들을 10개 정도 묶으려고 하는데
    방법을 아무리 찾아봐도 없어서.. 혹시 어떻게 하면되는지 아시나요?
    • 프로필 사진
      2021.10.27 01:06 신고
      1) top_n=1를 쓴 이유는 가장 비중이 높은 토픽 1개를 볼거기 때문입니다. (그런데 사실 top_n=1을 생략해도 상관없어요.) get_topics(top_n=1)[0]은 top_n개 토픽 목록중 0번째, 즉 가장 높은 토픽을 선택하는 거구요, get_topics(top_n=1)[0][0]은 그 토픽의 번호, get_topics(top_n=1)[0][1]은 그 토픽의 비중이 됩니다. 직접 get_topics() 값을 찍어보시면 이해하시기 쉬울거에요.

      2) 토픽별로 비중이 높은 문서라는 게 이상하네요. 각 문서가 여러 토픽을 가지는 것이지 토픽이 문서를 가지는게 아니거든요.
      본문의 코드가 문서들을 토픽#0의 비중이 가장 높은 문서들의 집합, 토픽#1의 비중이 가장 높은 문서들의 집합, ... 토픽 #n의 비중이 가장 높은 문서들의 집합으로 묶는 건데요, 이 작업이 원하시는 작업이 아닐까 싶네요.
  • 프로필 사진
    2021.11.04 19:49
    선생님 안녕하세요. 잘 배우고 있습니다. 그런데 궁금한 점이 있어서 댓글 남겼어요 . 알파와 함께 있는 에타(eta)값이 일반적인 토픽모델링 공식에서 '베타'로 나타나는 부분과 동일한지요? 즉, 코드에서 eta가 토픽모델링 공식에서 beta인 것으로 이해하면 될 지 문의드립니다.

    검색해보니, 알파는 문서별 토픽의 할당에 직접 영향을 주는 값이고, 베타는 토픽별 단어의 할당에 직접 영향을 주는 값이라고 나와서요.

    제가 잘 몰라서 문의드렸습니다. 답변주시면 참으로 감사하겠습니다.
    • 프로필 사진
      2021.11.04 21:01 신고
      네, 논문에 따라 `베타`로 표기하는 경우도 있도 `에타`로 표기하는 경우도 있더라구요. 여기에서는 토픽별 단어 분포에 연관되는 파라미터를 `에타`로 표시하였구요, 말씀하신 베타와 동일한 개념입니다.