Introducción
En este laboratorio, aplicaremos la Factorización de Matriz No Negativa (NMF, por sus siglas en inglés) y la Asignación Latente de Dirichlet (LDA, por sus siglas en inglés) en un corpus de documentos para extraer modelos aditivos de la estructura temática del corpus. La salida será una gráfica de temas, cada uno representado como un gráfico de barras utilizando las primeras palabras basadas en los pesos.
Consejos sobre la VM
Una vez que se haya iniciado la VM, haga clic en la esquina superior izquierda para cambiar a la pestaña Cuaderno y acceder a Jupyter Notebook para practicar.
A veces, es posible que tenga que esperar unos segundos para que Jupyter Notebook termine de cargarse. La validación de las operaciones no se puede automatizar debido a las limitaciones de Jupyter Notebook.
Si tiene problemas durante el aprendizaje, no dude en preguntar a Labby. Deje sus comentarios después de la sesión y lo resolveremos rápidamente para usted.
Cargar el Conjunto de Datos
Cargaremos el conjunto de datos 20 newsgroups y lo vectorizaremos. Utilizamos algunas heurísticas para filtrar términos inútiles desde el principio: se eliminan los encabezados, pies de página y respuestas citadas de los mensajes, y se eliminan las palabras comunes en inglés, las palabras que aparecen en solo un documento o en al menos el 95% de los documentos.
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]
Extraer Características
Extraeremos las características del conjunto de datos utilizando características tf-idf para NMF y características de recuento de términos brutos para LDA.
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
## Utilizar características tf-idf para 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)
## Utilizar características de recuento de términos brutos para 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)
Aplicar NMF
Aplicaremos NMF con dos funciones objetivo diferentes: la norma de Frobenius y la divergencia generalizada de Kullback-Leibler. Esta última es equivalente a la Indexación Semántica Latente Probabilística.
from sklearn.decomposition import NMF
n_components = 10
n_top_words = 20
init = "nndsvda"
## Ajustar el modelo NMF
print(
"Ajustando el modelo NMF (norma de Frobenius) con características tf-idf, "
"n_samples=%d y 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)
## Graficar las principales palabras para el modelo 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"Tema {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, "Temas en el modelo NMF (norma de Frobenius)"
)
## Ajustar el modelo NMF con la divergencia generalizada de Kullback-Leibler
print(
"\n" * 2,
"Ajustando el modelo NMF (divergencia generalizada de Kullback-Leibler "
"divergencia) con características tf-idf, n_samples=%d y 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)
## Graficar las principales palabras para el modelo NMF con la divergencia generalizada de Kullback-Leibler
tfidf_feature_names = tfidf_vectorizer.get_feature_names_out()
plot_top_words(
nmf,
tfidf_feature_names,
n_top_words,
"Temas en el modelo NMF (divergencia generalizada de Kullback-Leibler divergencia)",
)
## Ajustar el modelo MiniBatchNMF
from sklearn.decomposition import MiniBatchNMF
batch_size = 128
print(
"\n" * 2,
"Ajustando el modelo MiniBatchNMF (norma de Frobenius) con tf-idf "
"características, n_samples=%d y 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)
## Graficar las principales palabras para el modelo MiniBatchNMF con la norma de Frobenius
tfidf_feature_names = tfidf_vectorizer.get_feature_names_out()
plot_top_words(
mbnmf,
tfidf_feature_names,
n_top_words,
"Temas en el modelo MiniBatchNMF (norma de Frobenius)",
)
## Ajustar el modelo MiniBatchNMF con la divergencia generalizada de Kullback-Leibler
print(
"\n" * 2,
"Ajustando el modelo MiniBatchNMF (divergencia generalizada de Kullback-Leibler "
"divergencia) con características tf-idf, n_samples=%d y 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)
## Graficar las principales palabras para el modelo MiniBatchNMF con la divergencia generalizada de Kullback-Leibler
tfidf_feature_names = tfidf_vectorizer.get_feature_names_out()
plot_top_words(
mbnmf,
tfidf_feature_names,
n_top_words,
"Temas en el modelo MiniBatchNMF (divergencia generalizada de Kullback-Leibler divergencia)",
)
Aplicar LDA
Aplicaremos modelos LDA con características tf.
from sklearn.decomposition import LatentDirichletAllocation
print(
"\n" * 2,
"Ajustando modelos LDA con características tf, n_samples=%d y 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("hecho en %0.3fs." % (time() - t0))
tf_feature_names = tf_vectorizer.get_feature_names_out()
plot_top_words(lda, tf_feature_names, n_top_words, "Temas en el modelo LDA")
Resumen
En este laboratorio, hemos aprendido cómo aplicar la Factorización de Matriz No Negativa y la Asignación Latente de Dirichlet en un corpus de documentos para extraer modelos aditivos de la estructura temática del corpus. También hemos aprendido cómo graficar los temas, cada uno representado como un gráfico de barras utilizando las primeras palabras basadas en los pesos.