Как получить topi c нового документа в модели LDA - PullRequest
0 голосов
/ 26 марта 2020

Как передать документ .txt, предоставленный пользователем, динамически в модели LDA? Я пробовал приведенный ниже код, но он не работает, чтобы дать правильные topi c из do c. Topi c моего .txt относится к Sports , поэтому ему следует дать имя topi c как Sports. Это дает вывод как:

Score: 0.5569453835487366   - Topic: 0.008*"bike" + 0.005*"game" + 0.005*"team" + 0.004*"run" + 0.004*"virginia"
Score: 0.370819091796875    - Topic: 0.016*"game" + 0.014*"team" + 0.011*"play" + 0.008*"hockey" + 0.008*"player"
Score: 0.061239391565322876  -Topic: 0.010*"card" + 0.010*"window" + 0.008*"driver" + 0.007*"sale" + 0.006*"price"*
data = df.content.values.tolist()
data = [re.sub('\S*@\S*\s?', '', sent) for sent in data]
data = [re.sub('\s+', ' ', sent) for sent in data]
data = [re.sub("\'", "", sent) for sent in data]

def sent_to_words(sentences):
    for sentence in sentences:
        yield(gensim.utils.simple_preprocess(str(sentence), deacc=True))  # deacc=True removes punctuations

data_words = list(sent_to_words(data))
bigram = gensim.models.Phrases(data_words, min_count=5, threshold=100) # higher threshold fewer phrases.
trigram = gensim.models.Phrases(bigram[data_words], threshold=100)  
bigram_mod = gensim.models.phrases.Phraser(bigram)
trigram_mod = gensim.models.phrases.Phraser(trigram)
def remove_stopwords(texts):
    return [[word for word in simple_preprocess(str(doc)) if word not in stop_words] for doc in texts]

def make_bigrams(texts):
    return [bigram_mod[doc] for doc in texts]

def make_trigrams(texts):
    return [trigram_mod[bigram_mod[doc]] for doc in texts]

def lemmatization(texts, allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV']):

    texts_out = []
    for sent in texts:
        doc = nlp(" ".join(sent)) 
        texts_out.append([token.lemma_ for token in doc if token.pos_ in allowed_postags])
    return texts_out
# Remove Stop Words
data_words_nostops = remove_stopwords(data_words)
# Form Bigrams
data_words_bigrams = make_bigrams(data_words_nostops)
data_lemmatized = lemmatization(data_words_bigrams, allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV'])

id2word = gensim.corpora.Dictionary(data_lemmatized)

texts = data_lemmatized

corpus = [id2word.doc2bow(text) for text in texts]
# Build LDA model
lda_model = gensim.models.ldamodel.LdaModel(corpus=corpus,
                                           id2word=id2word,
                                           num_topics=20, 
                                           random_state=100,
                                           update_every=1,
                                           chunksize=100,
                                           passes=10,
                                           alpha='auto',
                                           per_word_topics=True)

#f = io.open("text.txt", mode="r", encoding="utf-8")

p=open("text.txt", "r") #document by the user which is related to sports

if p.mode == 'r':
    content = p.read()

bow_vector = id2word.doc2bow(lemmatization(p))

for index, score in sorted(lda_model[bow_vector], key=lambda tup: -1*tup[1]):
    print("Score: {}\t Topic: {}".format(score, lda_model.print_topic(index, 5)))


Ответы [ 2 ]

1 голос
/ 26 марта 2020

Весь ваш код верен, но я думаю, что ваши ожидания от моделирования LDA могут быть немного неверными. То, что вы получили, является правильным!

Во-первых, вы использовали фразу "topi c name"; темы, которые генерирует LDA, не имеют имен, и у них нет простого сопоставления с метками данных, используемых для обучения модели. Это неконтролируемая модель, и часто вы обучаете LDA данным, на которых нет меток. Если ваш корпус содержит документы, принадлежащие классам A, B, C, D, и вы обучаете модель LDA выводить четыре темы L, M, N, O, из этого НЕ следует, что существует какое-то отображение, подобное:

A -> M
B -> L
C -> O
D -> N

Во-вторых, будьте осторожны с разницей между токенами и темами в выводе. Вывод LDA выглядит примерно так:

Topi c 1: 0,5 - 0,005 * "token_13" + 0,003 * "token_204" + ...

Topi c 2: 0,07 - 0.01 * "token_24" + 0.001 * "token_3" + ...

Другими словами, каждому документу дается вероятность принадлежности к каждой из тем. И каждый топи c состоит из суммы каждого жетона корпуса, взвешенного каким-либо образом для однозначного определения топи c.

Существует соблазн взглянуть на самые тяжело взвешенные жетоны в каждой топи c и интерпретировать темы как класс. Например:

# If you have:
topic_1 = 0.1*"dog" + 0.08*"cat" + 0.04*"snake"

# It's tempting to name topic_1 = pets

Но это очень сложно проверить и сильно зависит от интуиции человека. Более распространенное использование LDA - когда у вас нет меток, и вы хотите определить, какие документы семантически похожи друг на друга, без необходимости определения правильной метки класса для документов.

0 голосов
/ 31 марта 2020

Это работает для меня после большой попытки, прокомментируйте, если у вас есть что-то другое.

bow_vector = dictionary.doc2bow(preprocess(content))
q= lda_model[bow_vector]

from operator import itemgetter 
res = max(q, key = itemgetter(1))[0] 
res1 = max(q, key = itemgetter(1))[1] 

if (res  == 1 ):
    print("This .txt file is related to Politics/Government, Accuracy:",res1)
elif (res == 2) :
        print("This .txt file is related to sports, Accuracy:",res1)
elif res==3:
        print("This .txt file is related to Computer, Accuracy:",res1)
elif..... (so on)
 else.
...