bab2min / tomotopy

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

DTModel 사용 중 No document with timepoint error에 관하여 #175

Closed HenryYoon closed 2 years ago

HenryYoon commented 2 years ago

안녕하세요. 저는 지금 석사 학위논문 관련하여 데이터 분석 중에 있는데요.

데이터 특성 상 연도별 토픽 분포가 중요해서 현재 DTModel 메소드로 토픽 분석 중에 있습니다.

그런데 모델 돌리던 중에 이러한 에러가 발생하여 부득이 이슈에 올리게 되었습니다.

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
d:\Dropbox\coding\research\korean_president\src\snippet.ipynb 셀 8 in <cell line: 14>()
     [11](vscode-notebook-cell:/d%3A/Dropbox/coding/research/korean_president/src/snippet.ipynb#ch0000007?line=10) for line in docs:
     [12](vscode-notebook-cell:/d%3A/Dropbox/coding/research/korean_president/src/snippet.ipynb#ch0000007?line=11)     mdl.add_doc(line.split(' '))
---> [14](vscode-notebook-cell:/d%3A/Dropbox/coding/research/korean_president/src/snippet.ipynb#ch0000007?line=13) mdl.train(5)
     [16](vscode-notebook-cell:/d%3A/Dropbox/coding/research/korean_president/src/snippet.ipynb#ch0000007?line=15) doc = [mdl.make_doc(line.split(' '), timepoint=times) for line in docs]
     [18](vscode-notebook-cell:/d%3A/Dropbox/coding/research/korean_president/src/snippet.ipynb#ch0000007?line=17) topic_dist, ll = mdl.infer(doc)

RuntimeError: D:\a\tomotopy\tomotopy\src\TopicModel\DTModel.hpp (425): No document with timepoint = 1

참고로 제 소스 코드는 아래와 같이 작성했습니다.

import tomotopy as tp
import pandas as pd
from collections import Counter
import matplotlib.pyplot as plt

# df = pd.read_csv('../data/president.csv')
# docs = df['nouns'].to_list()
times = len(df['time'].unique())

mdl = tp.DTModel(tw=tp.TermWeight.IDF, k=20, t=times)
for line in docs:
    mdl.add_doc(line.split(' '))

mdl.train(5)

doc = [mdl.make_doc(line.split(' '), timepoint=times) for line in docs]

topic_dist, ll = mdl.infer(doc)

여기서 보면 특정 timepoint(제 코드의 경우 1)에서 문서가 없다고 에러가 뜨는데, 어떻게 하면 이 오류를 해결할 수 있을지 여쭙고 싶습니다.

추가적으로, 현재 저는 각 문서의 생성 연도를 데이터에 넣어서 그것을 반영하여 시간대를 나누고 싶은데, 어떻게 하면 input corpus에 이를 반영할 수 있을지 알려주시면 감사하겠습니다.

HenryYoon commented 2 years ago

자문자답입니다만...

example/dtm.py 코드 보면서 해결했습니다!

정보 공유 용으로 코드 공유해봅니다.

import tomotopy as tp
import numpy as np
import pandas as pd

df = pd.read_csv('../data/president.csv')

df1 = df[['noun','time']]
df1 = df1.dropna(axis=0)

time = df1['time'].unique()

# convert time to 0~66
d_time = {k:v for k,v in zip(time, range(len(time)))}
df1['time'] = df1['time'].replace(d_time)

def data_feeder(df):
    for idx, row in df.iterrows():
        yield row['noun'], None, {'timepoint':row['time']}

corpus = tp.utils.Corpus(tokenizer=tp.utils.SimpleTokenizer())
corpus.process(data_feeder(df1))

mdl = tp.DTModel(k=20, t=67, phi_var=1e-2, corpus=corpus)
mdl.train(0)

# Let's train the model
for i in range(0, 1000, 20):
    print('Iteration: {:04}, LL per word: {:.4}'.format(i, mdl.ll_per_word))
    mdl.train(20)
print('Iteration: {:04}, LL per word: {:.4}'.format(1000, mdl.ll_per_word))

여기서 Pandas의 DataFrame을 df.iterrows() 메소드를 통해 예제와 유사하게 코드를 짰고, 이는 아래와 같습니다.

def data_feeder(df):
    for idx, row in df.iterrows():
        yield row['noun'], None, {'timepoint':row['time']}

이렇게 해서 DTModel에 적합한 코드를 짰고, 실행 결과를 볼 수 있었습니다.

추가적으로 time의 경우 원 데이터에서는 1948~2016까지로 되어 있는 것을

# convert time to 0~66
d_time = {k:v for k,v in zip(time, range(len(time)))}
df1['time'] = df1['time'].replace(d_time)

통해서 0~66으로 바꾼 후 정상 작동한 것을 확인했습니다.

다들 유용해 쓰시길 바라겠습니다!