Introduction
Dans ce laboratoire, nous allons appliquer la factorisation de matrice non négative (NMF) et l'allocation de Dirichlet latente (LDA) sur un corpus de documents pour extraire des modèles additifs de la structure thématiques du corpus. La sortie sera un graphique de thèmes, chacun représenté sous forme d'un graphique en barres utilisant les quelques premiers mots en fonction des poids.
Conseils sur la VM
Une fois le démarrage de la VM terminé, cliquez dans le coin supérieur gauche pour basculer vers l'onglet Notebook pour accéder à Jupyter Notebook pour la pratique.
Parfois, vous devrez peut-être attendre quelques secondes pour que Jupyter Notebook ait fini de charger. La validation des opérations ne peut pas être automatisée en raison des limitations de Jupyter Notebook.
Si vous rencontrez des problèmes pendant l'apprentissage, n'hésitez pas à demander à Labby. Donnez votre feedback après la session, et nous résoudrons rapidement le problème pour vous.
Charger le jeu de données
Nous allons charger le jeu de données 20 newsgroups et le vectoriser. Nous utilisons quelques heuristiques pour éliminer précocement les termes inutiles : les messages sont dépouillés de leurs en-têtes, pieds de page et réponses citées, et les mots anglais courants, les mots apparaissant dans un seul document ou dans au moins 95 % des documents sont supprimés.
from sklearn.datasets import fetch_20newsgroups
n_samples = 2000
n_features = 1000
print("Chargement du jeu de données...")
data, _ = fetch_20newsgroups(
shuffle=True,
random_state=1,
remove=("headers", "footers", "quotes"),
return_X_y=True,
)
data_samples = data[:n_samples]
Extraire les caractéristiques
Nous allons extraire les caractéristiques à partir du jeu de données en utilisant les caractéristiques tf-idf pour la NMF et les comptes de termes bruts pour la LDA.
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
## Utiliser les caractéristiques tf-idf pour la NMF.
print("Extraction des caractéristiques tf-idf pour la 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)
## Utiliser les caractéristiques de comptage de termes bruts pour la LDA.
print("Extraction des caractéristiques tf pour la 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)
Appliquer la NMF
Nous allons appliquer la NMF avec deux fonctions objectifs différentes : la norme de Frobenius et la divergence générale de Kullback-Leibler. Cette dernière est équivalente à l'indexation sémantique latente probabiliste.
from sklearn.decomposition import NMF
n_components = 10
n_top_words = 20
init = "nndsvda"
## Ajuster le modèle NMF
print(
"Ajustement du modèle NMF (norme de Frobenius) avec des caractéristiques tf-idf, "
"n_samples=%d et 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)
## Tracer les mots les plus fréquents pour le modèle 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"Sujet {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, "Sujets dans le modèle NMF (norme de Frobenius)"
)
## Ajuster le modèle NMF avec la divergence générale de Kullback-Leibler
print(
"\n" * 2,
"Ajustement du modèle NMF (divergence générale de Kullback-Leibler "
"divergence) avec des caractéristiques tf-idf, n_samples=%d et 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)
## Tracer les mots les plus fréquents pour le modèle NMF avec la divergence générale de Kullback-Leibler
tfidf_feature_names = tfidf_vectorizer.get_feature_names_out()
plot_top_words(
nmf,
tfidf_feature_names,
n_top_words,
"Sujets dans le modèle NMF (divergence générale de Kullback-Leibler divergence)",
)
## Ajuster le modèle MiniBatchNMF
from sklearn.decomposition import MiniBatchNMF
batch_size = 128
print(
"\n" * 2,
"Ajustement du modèle MiniBatchNMF (norme de Frobenius) avec tf-idf "
"caractéristiques, n_samples=%d et 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)
## Tracer les mots les plus fréquents pour le modèle MiniBatchNMF avec la norme de Frobenius
tfidf_feature_names = tfidf_vectorizer.get_feature_names_out()
plot_top_words(
mbnmf,
tfidf_feature_names,
n_top_words,
"Sujets dans le modèle MiniBatchNMF (norme de Frobenius)",
)
## Ajuster le modèle MiniBatchNMF avec la divergence générale de Kullback-Leibler
print(
"\n" * 2,
"Ajustement du modèle MiniBatchNMF (divergence générale de Kullback-Leibler "
"divergence) avec des caractéristiques tf-idf, n_samples=%d et 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)
## Tracer les mots les plus fréquents pour le modèle MiniBatchNMF avec la divergence générale de Kullback-Leibler
tfidf_feature_names = tfidf_vectorizer.get_feature_names_out()
plot_top_words(
mbnmf,
tfidf_feature_names,
n_top_words,
"Sujets dans le modèle MiniBatchNMF (divergence générale de Kullback-Leibler divergence)",
)
Appliquer la LDA
Nous allons appliquer des modèles LDA avec des caractéristiques tf.
from sklearn.decomposition import LatentDirichletAllocation
print(
"\n" * 2,
"Ajustement des modèles LDA avec des caractéristiques tf, n_samples=%d et 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("terminé en %0.3fs." % (time() - t0))
tf_feature_names = tf_vectorizer.get_feature_names_out()
plot_top_words(lda, tf_feature_names, n_top_words, "Sujets dans le modèle LDA")
Sommaire
Dans ce laboratoire, nous avons appris comment appliquer la factorisation de matrice non négative et l'allocation latente de Dirichlet sur un corpus de documents pour extraire des modèles additifs de la structure thémique du corpus. Nous avons également appris comment tracer les sujets, chacun représenté sous forme d'un graphique en barres en utilisant les quelques mots les plus fréquents en fonction des poids.