Построение графиков по извлечению тем с использованием NMF и LDA

Machine LearningMachine LearningBeginner
Практиковаться сейчас

This tutorial is from open-source community. Access the source code

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом лабе мы применим Негативный матричный разложение (Non-negative Matrix Factorization, NMF) и латентное Дирихлево распределение (Latent Dirichlet Allocation, LDA) к корпусу документов, чтобы извлечь аддитивные модели структуры тем корпуса. Результатом будет график тем, каждая из которых представлена в виде столбчатой диаграммы с использованием нескольких первых слов по весам.

Советы по работе с ВМ

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

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

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


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL sklearn(("Sklearn")) -.-> sklearn/DataPreprocessingandFeatureEngineeringGroup(["Data Preprocessing and Feature Engineering"]) sklearn(("Sklearn")) -.-> sklearn/AdvancedDataAnalysisandDimensionalityReductionGroup(["Advanced Data Analysis and Dimensionality Reduction"]) sklearn(("Sklearn")) -.-> sklearn/UtilitiesandDatasetsGroup(["Utilities and Datasets"]) ml(("Machine Learning")) -.-> ml/FrameworkandSoftwareGroup(["Framework and Software"]) sklearn/DataPreprocessingandFeatureEngineeringGroup -.-> sklearn/feature_extraction("Feature Extraction") sklearn/AdvancedDataAnalysisandDimensionalityReductionGroup -.-> sklearn/decomposition("Matrix Decomposition") sklearn/UtilitiesandDatasetsGroup -.-> sklearn/datasets("Datasets") ml/FrameworkandSoftwareGroup -.-> ml/sklearn("scikit-learn") subgraph Lab Skills sklearn/feature_extraction -.-> lab-49319{{"Построение графиков по извлечению тем с использованием NMF и LDA"}} sklearn/decomposition -.-> lab-49319{{"Построение графиков по извлечению тем с использованием NMF и LDA"}} sklearn/datasets -.-> lab-49319{{"Построение графиков по извлечению тем с использованием NMF и LDA"}} ml/sklearn -.-> lab-49319{{"Построение графиков по извлечению тем с использованием NMF и LDA"}} end

Загрузка датасета

Мы загрузим датасет 20 newsgroups и векторизуем его. Мы используем несколько эвристик для предварительного фильтрации бесполезных терминов: из постов удаляются заголовки, подписи и цитируемые ответы, а также общие английские слова, слова, встречающиеся только в одном документе или в по крайней мере 95% документов.

from sklearn.datasets import fetch_20newsgroups

n_samples = 2000
n_features = 1000

print("Loading dataset...")
data, _ = fetch_20newsgroups(
    shuffle=True,
    random_state=1,
    remove=("headers", "footers", "quotes"),
    return_X_y=True,
)
data_samples = data[:n_samples]

Извлечение признаков

Мы будем извлекать признаки из датасета, используя tf-idf признаки для NMF и признаки подсчета исходных терминов для LDA.

from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer

## Используем tf-idf признаки для NMF.
print("Extracting tf-idf features for NMF...")
tfidf_vectorizer = TfidfVectorizer(
    max_df=0.95, min_df=2, max_features=n_features, stop_words="english"
)
tfidf = tfidf_vectorizer.fit_transform(data_samples)

## Используем признаки подсчета исходных терминов для LDA.
print("Extracting tf features for LDA...")
tf_vectorizer = CountVectorizer(
    max_df=0.95, min_df=2, max_features=n_features, stop_words="english"
)
tf = tf_vectorizer.fit_transform(data_samples)

Применение NMF

Мы применим NMF с двумя различными целевыми функциями: нормой Фробениуса и обобщенным дивергенцией Куллбека-Лейблера. Последняя эквивалентна Вероятностному латентному семантическому индексированию (Probabilistic Latent Semantic Indexing).

from sklearn.decomposition import NMF

n_components = 10
n_top_words = 20
init = "nndsvda"

## Обучаем модель NMF
print(
    "Обучаем модель NMF (норма Фробениуса) с tf-idf признаками, "
    "n_samples=%d и n_features=%d..." % (n_samples, n_features)
)
nmf = NMF(
    n_components=n_components,
    random_state=1,
    init=init,
    beta_loss="frobenius",
    alpha_W=0.00005,
    alpha_H=0.00005,
    l1_ratio=1,
).fit(tfidf)

## Строим график топовых слов для модели NMF
def plot_top_words(model, feature_names, n_top_words, title):
    fig, axes = plt.subplots(2, 5, figsize=(30, 15), sharex=True)
    axes = axes.flatten()
    for topic_idx, topic in enumerate(model.components_):
        top_features_ind = topic.argsort()[: -n_top_words - 1 : -1]
        top_features = [feature_names[i] for i in top_features_ind]
        weights = topic[top_features_ind]

        ax = axes[topic_idx]
        ax.barh(top_features, weights, height=0.7)
        ax.set_title(f"Тема {topic_idx +1}", fontdict={"fontsize": 30})
        ax.invert_yaxis()
        ax.tick_params(axis="both", which="major", labelsize=20)
        for i in "top right left".split():
            ax.spines[i].set_visible(False)
        fig.suptitle(title, fontsize=40)

    plt.subplots_adjust(top=0.90, bottom=0.05, wspace=0.90, hspace=0.3)
    plt.show()

tfidf_feature_names = tfidf_vectorizer.get_feature_names_out()
plot_top_words(
    nmf, tfidf_feature_names, n_top_words, "Темы в модели NMF (норма Фробениуса)"
)

## Обучаем модель NMF с обобщенной дивергенцией Куллбека-Лейблера
print(
    "\n" * 2,
    "Обучаем модель NMF (обобщенная дивергенция Куллбека-Лейблера) "
    "с tf-idf признаками, n_samples=%d и n_features=%d..."
    % (n_samples, n_features),
)
nmf = NMF(
    n_components=n_components,
    random_state=1,
    init=init,
    beta_loss="kullback-leibler",
    solver="mu",
    max_iter=1000,
    alpha_W=0.00005,
    alpha_H=0.00005,
    l1_ratio=0.5,
).fit(tfidf)

## Строим график топовых слов для модели NMF с обобщенной дивергенцией Куллбека-Лейблера
tfidf_feature_names = tfidf_vectorizer.get_feature_names_out()
plot_top_words(
    nmf,
    tfidf_feature_names,
    n_top_words,
    "Темы в модели NMF (обобщенная дивергенция Куллбека-Лейблера)",
)

## Обучаем модель MiniBatchNMF
from sklearn.decomposition import MiniBatchNMF

batch_size = 128

print(
    "\n" * 2,
    "Обучаем модель MiniBatchNMF (норма Фробениуса) с tf-idf "
    "признаками, n_samples=%d и n_features=%d, batch_size=%d..."
    % (n_samples, n_features, batch_size),
)
mbnmf = MiniBatchNMF(
    n_components=n_components,
    random_state=1,
    batch_size=batch_size,
    init=init,
    beta_loss="frobenius",
    alpha_W=0.00005,
    alpha_H=0.00005,
    l1_ratio=0.5,
).fit(tfidf)

## Строим график топовых слов для модели MiniBatchNMF с нормой Фробениуса
tfidf_feature_names = tfidf_vectorizer.get_feature_names_out()
plot_top_words(
    mbnmf,
    tfidf_feature_names,
    n_top_words,
    "Темы в модели MiniBatchNMF (норма Фробениуса)"
)

## Обучаем модель MiniBatchNMF с обобщенной дивергенцией Куллбека-Лейблера
print(
    "\n" * 2,
    "Обучаем модель MiniBatchNMF (обобщенная дивергенция Куллбека-Лейблера) "
    "с tf-idf признаками, n_samples=%d и n_features=%d, "
    "batch_size=%d..." % (n_samples, n_features, batch_size),
)
mbnmf = MiniBatchNMF(
    n_components=n_components,
    random_state=1,
    batch_size=batch_size,
    init=init,
    beta_loss="kullback-leibler",
    alpha_W=0.00005,
    alpha_H=0.00005,
    l1_ratio=0.5,
).fit(tfidf)

## Строим график топовых слов для модели MiniBatchNMF с обобщенной дивергенцией Куллбека-Лейблера
tfidf_feature_names = tfidf_vectorizer.get_feature_names_out()
plot_top_words(
    mbnmf,
    tfidf_feature_names,
    n_top_words,
    "Темы в модели MiniBatchNMF (обобщенная дивергенция Куллбека-Лейблера)"
)

Применение LDA

Мы применим модели LDA с tf признаками.

from sklearn.decomposition import LatentDirichletAllocation

print(
    "\n" * 2,
    "Обучаем модели LDA с tf признаками, n_samples=%d и n_features=%d..."
    % (n_samples, n_features),
)
lda = LatentDirichletAllocation(
    n_components=n_components,
    max_iter=5,
    learning_method="online",
    learning_offset=50.0,
    random_state=0,
)
t0 = time()
lda.fit(tf)
print("завершено за %0.3fs." % (time() - t0))

tf_feature_names = tf_vectorizer.get_feature_names_out()
plot_top_words(lda, tf_feature_names, n_top_words, "Темы в модели LDA")

Резюме

В этом практическом занятии мы научились применять Негативный матричный разложение (Non-negative Matrix Factorization) и латентное Дирихлево распределение (Latent Dirichlet Allocation) к корпусу документов для извлечения аддитивных моделей структуры тем корпуса. Мы также научились строить графики тем, каждая из которых представлена в виде столбчатой диаграммы с использованием нескольких первых слов, отсортированных по весам.