В этом посте мы узнаем, как определить, какая тема обсуждается в документе, что называется тематическим моделированием. В частности, мы рассмотрим Скрытое распределение Дирихле (LDA): широко используемый метод тематического моделирования. И мы применим LDA для преобразования набора исследовательских работ в набор тем.

Тематическое моделирование исследовательской работы - это метод машинного обучения без учителя, который помогает нам обнаруживать скрытые семантические структуры в статье, что позволяет нам изучать тематические представления статей в корпусе. Модель может применяться к любым типам меток на документах, например к тегам на сообщениях на веб-сайте.

Процесс

  • Мы заранее выбираем количество тем, даже если не знаем, какие именно темы.
  • Каждый документ представлен в виде распределения по темам.
  • Каждая тема представлена ​​в виде распределения по словам.

Текстовые данные исследовательской работы - это просто набор текстов без надписей, которые можно найти здесь.

Очистка текста

Мы используем следующую функцию для очистки наших текстов и возврата списка токенов:

import spacy
spacy.load('en')
from spacy.lang.en import English
parser = English()
def tokenize(text):
    lda_tokens = []
    tokens = parser(text)
    for token in tokens:
        if token.orth_.isspace():
            continue
        elif token.like_url:
            lda_tokens.append('URL')
        elif token.orth_.startswith('@'):
            lda_tokens.append('SCREEN_NAME')
        else:
            lda_tokens.append(token.lower_)
    return lda_tokens

Мы используем Wordnet НЛТК, чтобы найти значения слов, синонимов, антонимов и т. Д. Кроме того, мы используем WordNetLemmatizer для получения корневого слова.

import nltk
nltk.download('wordnet')
from nltk.corpus import wordnet as wn
def get_lemma(word):
    lemma = wn.morphy(word)
    if lemma is None:
        return word
    else:
        return lemma
    
from nltk.stem.wordnet import WordNetLemmatizer
def get_lemma2(word):
    return WordNetLemmatizer().lemmatize(word)

Отфильтровать стоп-слова:

nltk.download('stopwords')
en_stop = set(nltk.corpus.stopwords.words('english'))

Теперь мы можем определить функцию для подготовки текста к моделированию темы:

def prepare_text_for_lda(text):
    tokens = tokenize(text)
    tokens = [token for token in tokens if len(token) > 4]
    tokens = [token for token in tokens if token not in en_stop]
    tokens = [get_lemma(token) for token in tokens]
    return tokens

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

Теперь мы можем увидеть, как преобразуются наши текстовые данные:

import random
text_data = []
with open('dataset.csv') as f:
    for line in f:
        tokens = prepare_text_for_lda(line)
        if random.random() > .99:
            print(tokens)
            text_data.append(tokens)

['sociocrowd', 'social', 'network', 'base', 'framework', 'толпа', 'симуляция']
['обнаружение', 'техника', 'часы', ' восстановление ',' приложение ']
[' напряжение ',' слоговое ',' компандирование ',' область ',' фильтр ']
[' перцепционное ',' базовое ',' кодирование ',' решение ']
[' когнитивный ',' мобильный ',' виртуальный ',' сетевой ',' оператор ',' инвестиции ',' ценообразование ',' предложение ',' неопределенность ']
[' кластеризация »,« запрос »,« поиск »,« движок »]
[« психологический »,« вовлеченность »,« предприятие »,« начало »,« лондон »]
[« 10 бит » , '200 мс', 'в цифровом виде', 'калибровка', 'конвейерная', 'с использованием', 'переключение', 'операционные усилители']
['оптимальный', 'распределение', 'ресурс', 'распределить ',' информация ',' сеть ']
[' моделирование ',' синаптический ',' пластичность ',' внутри ',' сеть ',' высоко ',' ускорять ',' если ',' нейрон ' ]
['плитка', 'чередование', 'мульти', 'уровень', 'дискретный', 'вейвлет', 'преобразование']
['безопасность', 'перекрестие', 'слой' , 'протокол', 'беспроводной', 'датчик', 'сеть']
['объективность', 'промышленный', 'exhi бит ']
[' баланс ',' пакет ',' сбросить ',' улучшить ',' производительность ',' сеть ']
[' bodyqos ',' адаптивный ',' радио ',' агностик ',' датчик ',' сеть ']
[' дизайн ',' надежность ',' методология ']
[' контекст ',' осведомленность ',' изображение ',' семантика ',' извлечение »,« социальный »]
[« вычисление »,« нестабильный »,« предел »,« цикл »,« большой »,« масштаб »,« мощность »,« система »,« модель »]
['фотон', 'плотность', 'оценка', 'использование', 'множественный', 'важность', 'выборка']
['подход', 'сустав', 'слепой', 'пробел ',' выравнивание ',' оценка ']
[' унифицировать ',' квадратичный ',' программирование ',' подход ',' смешать ',' размещение ']

LDA с Gensim

Сначала мы создаем словарь из данных, затем преобразуем его в корпус мешок слов и сохраняем словарь и корпус для будущего использования.

from gensim import corpora
dictionary = corpora.Dictionary(text_data)corpus = [dictionary.doc2bow(text) for text in text_data]
import pickle
pickle.dump(corpus, open('corpus.pkl', 'wb'))
dictionary.save('dictionary.gensim')

Мы просим LDA найти в данных 5 тем:

import gensim
NUM_TOPICS = 5
ldamodel = gensim.models.ldamodel.LdaModel(corpus, num_topics = NUM_TOPICS, id2word=dictionary, passes=15)
ldamodel.save('model5.gensim')
topics = ldamodel.print_topics(num_words=4)
for topic in topics:
    print(topic)

(0, '0,034 * "процессор" + 0,019 * "база данных" + 0,019 * "проблема" + 0,019 * "обзор"')
(1, '0,051 * "компьютер" + 0,028 * "дизайн «+ 0,028 *» графика »+ 0,028 *« галерея »')
(2,' 0,050 *« управление »+ 0,027 *« объект »+ 0,027 *« схема »+ 0,027 *« эффективный »')
(3, '0,019 * «когнитивный» + 0,019 * «радио» + 0,019 * «сеть» + 0,019 * «распространять»')
(4, '0,029 * «схема» + 0,029 * «система» + 0,029 * «строгая» + 0,029 * «интеграция» »)

Тема 0 включает такие слова, как «процессор», «база данных», «проблема» и «обзор», звучит как тема, связанная с базой данных. Тема 1 включает такие слова, как «компьютер», «дизайн», «графика» и «галерея», это определенно тема, связанная с графическим дизайном. Тема 2 включает такие слова, как «менеджмент», «объект», «схема» и «эффективный», что звучит как тема, связанная с корпоративным управлением. И так далее.

С LDA мы можем видеть, что разные документы с разными темами, и различия очевидны.

Давайте попробуем новый документ:

new_doc = 'Practical Bayesian Optimization of Machine Learning Algorithms'
new_doc = prepare_text_for_lda(new_doc)
new_doc_bow = dictionary.doc2bow(new_doc)
print(new_doc_bow)
print(ldamodel.get_document_topics(new_doc_bow))

[(38, 1), (117, 1)]
[(0, 0.06669136), (1, 0.40170625), (2, 0.06670282), (3, 0.39819494), (4, 0.066704586)]

Мой новый документ посвящен алгоритмам машинного обучения, результаты LDA показывают, что тема 1 имеет наивысшую вероятность, а тема 3 имеет вторую по величине вероятность. Мы согласились!

Помните, что в сумме вышеуказанные 5 вероятностей дают 1.

Теперь мы просим LDA найти в данных 3 темы:

ldamodel = gensim.models.ldamodel.LdaModel(corpus, num_topics = 3, id2word=dictionary, passes=15)
ldamodel.save('model3.gensim')
topics = ldamodel.print_topics(num_words=4)
for topic in topics:
    print(topic)

(0, '0,029 * "процессор" + 0,016 * "управление" + 0,016 * "помощь" + 0,016 * "алгоритм"')
(1, '0,026 * "радио" + 0,026 * "сеть «+ 0,026 *« когнитивный »+ 0,026 *« эффективный »')
(2,' 0,029 *« схема »+ 0,029 *« распределить »+ 0,016 *« база данных »+ 0,016 *« управление »')

Мы также можем найти 10 тем:

ldamodel = gensim.models.ldamodel.LdaModel(corpus, num_topics = 10, id2word=dictionary, passes=15)
ldamodel.save('model10.gensim')
topics = ldamodel.print_topics(num_words=4)
for topic in topics:
    print(topic)

(0, '0,055 * «база данных» + 0,055 * «система» + 0,029 * «технический» + 0,029 * «рекурсивный»')
(1, '0,038 * «распределить» + 0,038 * »графику «+ 0,038 *» восстановить »+ 0,038 *« точно »')
(2,' 0,055 *« управление »+ 0,029 *« многоверсия »+ 0,029 *« ссылка »+ 0,029 *« документ »')
(3, '0,046 * «схема» + 0,046 * «объект» + 0,046 * «генерация» + 0,046 * «преобразование»')
(4, '0,008 * «программирование» + 0,008 * «схема» + 0,008 * «сеть» + 0,008 * «поверхность» ')
(5,' 0,061 * «радио» + 0,061 * «когнитивный» + 0,061 * «сеть» + 0,061 * «возможность подключения»)
(6, '0,085 * "программирование" + 0,008 * "схема" + 0,008 * "подраздел" + 0,008 * "управление"')
(7, '0,041 * "схема" + 0,041 * "конструкция" + 0,041 * «процессор» + 0,041 * «инструкция» ')
(8,' 0,055 * «компьютер» + 0,029 * «эффективный» + 0,029 * «канал» + 0,029 * «сотрудничество» ')
(9, '0,061 * «стимуляция» + 0,061 * «датчик» + 0,061 * «сетчатка» + 0,061 * «пиксель»')

pyLDAvis

PyLDAvis разработан, чтобы помочь пользователям интерпретировать темы в тематической модели, которая соответствует корпусу текстовых данных. Пакет извлекает информацию из подобранной тематической модели LDA для создания интерактивной веб-визуализации.

Визуализируем 5 тем:

dictionary = gensim.corpora.Dictionary.load('dictionary.gensim')
corpus = pickle.load(open('corpus.pkl', 'rb'))
lda = gensim.models.ldamodel.LdaModel.load('model5.gensim')
import pyLDAvis.gensim
lda_display = pyLDAvis.gensim.prepare(lda, corpus, dictionary, sort_topics=False)
pyLDAvis.display(lda_display)

Важность: мера того, насколько термин говорит вам о теме.

Релевантность: средневзвешенное значение вероятности слова в теме и слова в теме, нормированное на вероятность этой темы.

Размер пузыря определяет важность тем по отношению к данным.

Во-первых, у нас есть наиболее важные термины, то есть термины в основном рассказывают нам о том, что происходит по темам. Мы также можем рассмотреть индивидуальную тему.

Визуализируем 3 темы:

lda3 = gensim.models.ldamodel.LdaModel.load('model3.gensim')
lda_display3 = pyLDAvis.gensim.prepare(lda3, corpus, dictionary, sort_topics=False)
pyLDAvis.display(lda_display3)

Визуализируем 10 тем:

lda10 = gensim.models.ldamodel.LdaModel.load('model10.gensim')
lda_display10 = pyLDAvis.gensim.prepare(lda10, corpus, dictionary, sort_topics=False)
pyLDAvis.display(lda_display10)

Когда у нас есть 5 или 10 тем, мы можем видеть, что определенные темы сгруппированы вместе, это указывает на схожесть между темами. Какой прекрасный способ визуализировать то, что мы уже сделали!

Попробуйте, найдите набор текстовых данных, удалите метку, если она помечена, и создайте модель темы самостоятельно!

Исходный код можно найти на Github. Я с нетерпением жду любых отзывов или вопросов.