Сначала я не планировал писать о LDA, но, поскольку он часто упоминается в более поздних постах, я хотел дать краткий обзор. LDA, сокращение от Latent Dirichlet Allocation, представляет собой простой метод, используемый для поиска тем в текстовых документах. Его цель — обнаружить скрытые темы в группе документов. В этом посте мы углубимся и попытаемся дать некоторую интуицию концепции.

Что это такое?

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

1. Предварительная обработка

Перед применением LDA нам нужно предварительно обработать текстовые данные. Общие этапы предварительной обработки включают в себя:

  • Токенизация: разбейте текст на отдельные слова или токены.
  • Удаление стоп-слов: удалите общие слова, такие как «и», «в», «в» и т. д., которые не способствуют идентификации темы.
  • Stemming/Lemmatization: Сократите слова до их корневых форм, чтобы рассматривать различные формы слова как единое целое.

2. Инициализация:

Выберите количество тем «K», которые вы хотите обнаружить в коллекции документов. Каждая тема будет представлять собой распределение вероятностей по словам.

Пример. Предположим, у нас есть коллекция документов из 8 цитат из фильмов, и мы хотим открыть для себя 3 темы.

Doc1: "Here's looking at you, kid." -Casablanca
Doc2: "You can't handle the truth!" -A Few Good Men
Doc3: "There's no place like home." -The Wizard of Oz
Doc4: "Keep your friends close, but your enemies closer." -The Godfather Part II
Doc5: "Life is like a box of chocolates." -Forrest Gump
Doc6: "You had me at hello." -Jerry Maguire 
Doc7: "May the Force be with you." - Star Wars
Doc8: "I'm king of the world!" - Titanic

3. Произвольно назначьте темы каждому слову:

Первоначально назначьте каждое слово в документах одной из тем «K» случайным образом. Это дает начальное распределение тем для каждого документа и распределение слов для каждой темы.

Doc1: "Here's(T1) looking(T3) at(T2) you(T1), kid(T3)." -Casablanca
Doc2: "You(T1) can't(T2) handle(T3) the(T1) truth(T2)!" -A Few Good Men
Doc3: "There's(T3) no(T1) place(T2) like(T3) home(T1)." -The Wizard of Oz
Doc4: "Keep(T2) your(T3) friends(T1) close(T2), but(T3) your(T1) enemies(T2) closer(T3)." -The Godfather Part II
Doc5: "Life(T1) is(T2) like(T3) a(T1) box(T2) of(T3) chocolates(T1)." -Forrest Gump
Doc6: "You(T3) had(T1) me(T2) at(T3) hello(T1)." -Jerry Maguire
Doc7: "May(T2) the(T3) Force(T1) be(T2) with(T3) you(T1)." -Star Wars
Doc8: "I'm(T3) king(T1) of(T2) the(T3) world(T1)!" -Titanic

4. Повторно обновляйте назначения тем:

Используйте следующие две вероятности, чтобы обновить назначения тем для каждого слова:

а. P(тема t | документ d): доля слов в документе d, отнесенная к теме t.

б. P(слово w | тема t): доля слов в теме t, которые совпадают со словом w.

Повторяйте этот процесс в течение предварительно определенного количества итераций или до тех пор, пока назначения тем не сойдутся. Во время каждой итерации переназначайте каждое слово теме с вероятностью, пропорциональной произведению двух вышеуказанных вероятностей.

5. Извлеките темы и их распределение слов:

После итеративного процесса вы получите стабильные темы с их распределением слов. Эти темы представляют основные темы в коллекции документов. В нашем примере LDA может генерировать темы, подобные следующим:

Topic 1: love, relationships, home, friends, enemies, truth
Topic 2: movies, world, Force, king
Topic 3: greetings, looking, hello

6. Назначьте темы документам:

Для каждого документа назначьте тему с наибольшей долей слов в этом документе.

Doc1: Topic 1 (Love & Relationships)
Doc2: Topic 1 (Love & Relationships)
Doc3: Topic 1 (Love & Relationships)
Doc4: Topic 1 (Love & Relationships)
Doc5: Topic 1 (Love & Relationships)
Doc6: Topic 3 (Greetings & Expressions)
Doc7: Topic 2 (Movies & Adventure)
Doc8: Topic 2 (Movies & Adventure)

Визуальное представление

Для визуального представления LDA можно использовать матрицу, в которой строки представляют документы, а столбцы представляют обнаруженные темы. Каждая ячейка содержит вероятность соответствующей темы для этого документа.

          Topic 1   Topic 2    Topic 3
Doc1:   [  0.58       0.34      0.08  ]
Doc2:   [  0.85       0.15      0.15  ]
Doc3:   [  0.62       0.12      0.26  ]
Doc4:   [  0.46       0.21      0.33  ]
Doc5:   [  0.40       0.29      0.31  ]
Doc6:   [  0.35       0.16      0.49  ]
Doc7:   [  0.05       0.90      0.05  ]
Doc8:   [  0.01       0.98      0.01  ]

В этой матрице каждая строка представляет документ, а каждый столбец — тему. Значения в ячейках представляют долю каждой темы в соответствующем документе. Например, в Doc1 доля темы 1 составляет 0,58, а доля тем 2 и 3 — 0,34 и 0,08 соответственно. Это указывает на то, что Doc1 в основном посвящен теме 1 (Любовь и отношения).

Другой способ визуализировать LDA — отобразить темы в низкоразмерном пространстве, таком как двумерная плоскость, с использованием методов уменьшения размерности, таких как t-SNE или PCA. Каждая точка на графике представляет собой документ, и документы с похожими темами будут сгруппированы вместе.

import gensim
import numpy as np
from gensim import corpora
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt

# Preprocessing the text
processed_docs = [gensim.utils.simple_preprocess(doc) for doc in documents]

# Creating a dictionary from the processed documents
dictionary = corpora.Dictionary(processed_docs)

# Converting the processed documents into a document-term matrix (BoW representation)
corpus = [dictionary.doc2bow(doc) for doc in processed_docs]

# Training the LDA model
num_topics = 3
lda_model = gensim.models.LdaModel(corpus, num_topics=num_topics, id2word=dictionary, passes=10)

# Extract topic probabilities for each document
topic_probs = np.zeros((len(corpus), num_topics))
for idx, doc_bow in enumerate(corpus):
    for topic, prob in lda_model.get_document_topics(doc_bow):
        topic_probs[idx, topic] = prob

# Dimensionality reduction using t-SNE
tsne_model = TSNE(n_components=2, perplexity=5, random_state=42)
tsne_data = tsne_model.fit_transform(topic_probs)


# Plotting the 2D t-SNE representation
plt.scatter(tsne_data[:, 0], tsne_data[:, 1], c=np.argmax(topic_probs, axis=1), cmap='viridis', marker='o', s=100)
plt.title('t-SNE Visualization of Topic Clusters')
plt.xlabel('t-SNE Dimension 1')
plt.ylabel('t-SNE Dimension 2')
plt.show()

Код выполняет следующие шаги:

  • Предварительно обрабатывает текст в документах с помощью функции Gensim simple_preprocess.
  • Создает словарь из обработанных документов, используя класс corpora.Dictionary.
  • Преобразует обработанные документы в матрицу терминов документа (представление набора слов) с использованием метода doc2bow.
  • Обучает модель LDA, используя класс Gensim models.LdaModel с указанным количеством тем.
  • Извлекает вероятности тем для каждого документа, используя метод get_document_topics обученной модели LDA.

gensim — это библиотека Python, предназначенная для тематического моделирования и обработки естественного языка, предлагающая такие инструменты и алгоритмы, как LDA, для обработки текстовых данных. Модуль corpora, компонент Gensim, упрощает создание корпусов текстов и управление ими, упрощая создание словарей и преобразование документов в наборы слов. Между тем, модуль TSNE из scikit-learn используется для уменьшения размерности; его метод t-SNE сжимает многомерные данные, сохраняя при этом относительные расстояния, что делает его идеальным для визуализации тематических вероятностей на 2D-плоскости.

Результирующий график показывает документы в виде точек в 2D-пространстве с цветами, представляющими наиболее вероятную тему для каждого документа. Документы с похожими темами будут группироваться вместе, и t-SNE помогает визуализировать этот шаблон кластеризации. Это позволяет нам легче понять отношения между документами и их темами.