Тематическое моделирование с помощью Spacy — не дает очень хороших прогнозов

#python-3.x #nlp #spacy

#python-3.x #nlp #spacy

Вопрос:

Я работаю над задачей тематического моделирования, в которой я беру отзывы людей (текст) и пытаюсь извлечь из них важные темы.

Обратная связь довольно короткая, и я не знаю, является ли это тем, что ставит перед нами проблему. Ниже приведен мой код, есть ли что-то действительно очевидное, что я пропустил?

Я удаляю стоп-слова, лемматизирую, оставляю только существительные и удаляю стоп-слова. Однако я передаю их в модель, она работает не совсем так, как я надеялся

Одной из больших проблем является семантика, клиент может ссылаться на одно и то же понятие по-разному: магазин, бутик, магазин, супермаркет и т. Д… Все они относятся к магазину, но LDA рассматривает их как разные концепции и объединяет их в разные темы, хотя «Я люблю магазин» и «Я люблю магазин» — это одно и то же утверждение.

 import spacy
import pandas as pd
from textblob import TextBlob

#set display options
pd.set_option('display.max_colwidth', 0)
pd.set_option('display.max_rows', 0)

#ingest data
df = pd.read_csv('surv.csv')

#import spacy language library and stopword dictionary
nlp = spacy.load('en_core_web_sm')
all_stopwords = nlp.Defaults.stop_words

#Limit DF to columns of interest and drop nulls
responses = df[['Comment', 'score']]
responses = responses.dropna()

#lemmatize the strings
def cleanup(row):
    comment = row['Comment']
    comment = nlp(comment)
    sent = []
    for word in comment:
        sent.append(word.lemma_)    
    return " ".join(sent)

#keep only nouns
def only_nouns(row):
    comment = row['nostops']
    blob = TextBlob(comment)
    x = blob.noun_phrases
    return " ".join(x)

def pos(row):
    comment = row['nostops']
    comment = nlp(comment)
    nouns = []
    i=0
    while i < len(comment)-1:
        if comment[i].pos_ == 'NOUN':
            nouns.append(comment[i])
        i=i 1
    return nouns
        
#remove the stop words
def remove_stops(row):
    comment = row['Comment']
    comment = comment.split(' ')  
    rem = []
    for word in comment:
        if word not in all_stopwords:
            rem.append(word)
    return " ".join(rem)

#What entities are defined in the document
def split_entities(row):
    comment = row['Comment']
    comment = nlp(comment)
    entities = []
    for ent in comment.ents:
        entities.append(ent)
    return entities          

#Call functions
responses['lemmas'] = responses.apply(cleanup,axis=1)            
responses['nostops'] = responses.apply(remove_stops,axis=1)
responses['nouns'] = responses.apply(pos, axis=1)
responses['nouns2'] = responses.apply(only_nouns, axis=1)
responses['entities'] = responses.apply(split_entities,axis=1)


from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation
cv = CountVectorizer(max_df=0.9, min_df=2, stop_words='english') 
document_term_matrix = cv.fit_transform(responses['nouns'])
lda = LatentDirichletAllocation(n_components=4, random_state=42)
lda.fit(document_term_matrix)
topic_results = lda.transform(document_term_matrix) 
  

Ответ №1:

Общее предложение: вы пытались добавить TF-IDF в sklearn?Это хороший общий способ взвешивания слов на основе того, как часто они встречаются в документах и во всех документах, и это улучшает качество вывода LDA. Вы можете добавить его вместе с «CountVectorizer». Вот хороший полный пример из документов sklearn.

Конкретное предложение по вопросу слов, которые вы хотели бы рассматривать как синонимы («магазин, бутик, магазин, супермаркет»): я думаю, я бы добавил этап предварительной обработки, на котором я заменяю все эти отдельные слова одним и тем же токеном (например, преобразовать все вхождения «магазин, бутик,магазин, супермаркет» в «магазин»). Это требует ручного создания списков синонимов, но это простой способ решения проблемы.