bab2min / tomotopy

Python package of Tomoto, the Topic Modeling Tool
https://bab2min.github.io/tomotopy
MIT License
564 stars 63 forks source link

Tomotopy와 pyLDAvis를 연계할 수 있나요? #74

Closed FL3Xxxx closed 4 years ago

FL3Xxxx commented 4 years ago

저는 tomotopy hdp모델을 활용하고 있습니다.

pyLDAvis를 활용하기 위해서는 인자로 model, corpus, dictionary가 필요한데, tomotopy를 통해 학습된 모델을 넣으면 'tomotopy.HDPModel' object has no attribute 'num_topics' 문제가 발생합니다.

그 어떤 결과보다 tomotopy hdp모델이 결과가 좋아 꼭 활용하고 싶습니다. 연계가 가능할까요?

추가적으로 아래 과정과 같이 전처리가 완료되어 저장된 코퍼스의 문자열을 반환할 수 있을까요?

corpus = tp.utils.Corpus(
    tokenizer=tokenizer
)
# 입력 파일에는 한 줄에 문헌 하나씩이 들어가 있습니다.
corpus.process((line, kiwi.async_analyze(line)) for line in open('입력 텍스트 파일.txt', encoding='utf-8'))
# 전처리한 코퍼스를 저장한다.
corpus.save('k.cps')
bab2min commented 4 years ago

pyLDAvis를 이용하는 예시는 https://github.com/bab2min/tomotopy/blob/main/examples/lda_visualization.py 에 있습니다만, 이 예시는 LDA 모델을 대상으로 하고 있습니다. 불행히도 HDP 모델은 바로 pyLDAvis에 입력으로 넣을수가 없어서 위 예시를 그대로 사용하지는 못합니다. 대신 HDP 모델의 경우 모델을 LDA로 변환해주는 convert_to_lda라는 메소드를 제공합니다. 따라서 HDP로 학습한 뒤 해당 모델을 convert_to_lda를 사용해 LDA로 변환한 뒤 pyLDAvis에 넣으시면 되겠습니다.

hdpmodel = tp.HDPModel(**some_args)

# hdpmodel을 train합니다.

# 전체 토픽들 중 차지하는 비율이 0.001 미만은 토픽들은 제거하여 LDA모델로 변환합니다.
ldamodel, _ = hdpmodel.convert_to_lda(topic_threshold=0.001)

# pyLDAvis에 입력하여 시각화하기
topic_term_dists = np.stack([ldamodel.get_topic_word_dist(k) for k in range(ldamodel.k)])
doc_topic_dists = np.stack([doc.get_topic_dist() for doc in ldamodel.docs])
doc_lengths = np.array([len(doc.words) for doc in ldamodel.docs])
vocab = list(ldamodel.used_vocabs)
term_frequency = ldamodel.used_vocab_freq

prepared_data = pyLDAvis.prepare(
    topic_term_dists, 
    doc_topic_dists, 
    doc_lengths, 
    vocab, 
    term_frequency
)
pyLDAvis.save_html(prepared_data, 'ldavis.html')
bab2min commented 4 years ago

두번째 질문에 대해 답변드리자면, 현재 아쉽게도 Corpus클래스에서는 그런 기능을 제공하지 않습니다. 따라서 다음과 같이 직접 내부 변수에 접근하여 전처리된 내용을 확인하셔야 합니다.

# 여기서 doc_id는 0에서 len(corpus) - 1 사이의 정수값입니다.

[corpus._vocab.id2word[word_id] for word_id in corpus._docs[doc_id][0]] # 전처리 및 stemming된 단어 리스트를 보여줍니다.

corpus._docs[doc_id][1] # 전처리되기 이전의 raw text를 보여줍니다.

다음 업데이트에는 좀더 편하게 Corpus 내의 문서들에 접근할 수 있는 인터페이스를 추가하도록 해야겠네요. 좋은 질문에 감사드립니다.

FL3Xxxx commented 4 years ago

답변 정말 감사드립니다.

두 답변의 코드 모두 정상적으로 잘 작동하나, 마지막 시각화 부분에서 ValidationError:

https://stackoverflow.com/questions/47998685/pyldavis-validation-error-on-trying-to-visualize-topics 위 답변에 따르면 해당 문제는 hdp 모델에서 발생한다고 하는데, doc_topic_dists에 길이가 0인 문서가 많아서 해당 부분을 사전에 제거해야 한다고 합니다.

ldamodel.docs의 길이가 0 인 문서를 사전에 처리하는 방법이 있을까요?

혹은 모델에 사용되는 copus의 빈 행을 찾아서 제거할 수 있을까요?

FL3Xxxx commented 4 years ago

hdpmodel = tp.HDPModel(min_cf=0, tw=tp.TermWeight.IDF, corpus=corpus, rm_top = 5, seed = 1)

에서 rm_top 변수를 없애니 문제없이 작동함을 확인했습니다.

감사합니다.

Jiseong-Michael-Yang commented 4 years ago

안녕하세요? tomotopy 너무 잘 쓰고 있습니다 감사드립니다^^ 저도 비슷한 질문인데요, 저는 DMR 모델을 사용했는데 혹시 이것도 lda모델로 변환하여 pyLDAvis와 연계가 가능할까요?

bab2min commented 4 years ago

@Jiseong-Michael-Yang DMR 모델이라면 예제에 있는 LDA 시각화 코드(https://github.com/bab2min/tomotopy/blob/main/examples/lda_visualization.py )를 그대로 사용하셔도 무방합니다.

Jiseong-Michael-Yang commented 4 years ago

@bab2min 확인해본 결과 결과값이 잘 나옵니다. 답변 감사드립니다!