Introdução
Neste laboratório, utilizaremos o algoritmo de Co-agrupamento Espectral no conjunto de dados de 20 grupos de notícias para biclustering dos documentos. O conjunto de dados possui 20 categorias de documentos e excluiremos a categoria "comp.os.ms-windows.misc", pois contém mensagens sem dados. As mensagens vetorizadas usando TF-IDF formam uma matriz de frequência de palavras, que é então biclusterizada usando o algoritmo de Co-agrupamento Espectral de Dhillon. Os biclusters resultantes documento-palavra indicam subconjuntos de palavras usadas com mais frequência nesses subconjuntos de documentos. Também agruparemos os documentos usando MiniBatchKMeans para comparação.
Dicas da Máquina Virtual
Após o arranque da VM, clique no canto superior esquerdo para mudar para a aba Notebook para aceder ao Jupyter Notebook para a prática.
Por vezes, pode ser necessário esperar alguns segundos para o Jupyter Notebook terminar de carregar. A validação das operações não pode ser automatizada devido a limitações no Jupyter Notebook.
Se tiver problemas durante o aprendizado, sinta-se à vontade para perguntar ao Labby. Forneça feedback após a sessão e resolveremos prontamente o problema para si.
Importar Bibliotecas
Importaremos as bibliotecas necessárias para este laboratório.
from collections import defaultdict
import operator
from time import time
import numpy as np
from sklearn.cluster import SpectralCoclustering
from sklearn.cluster import MiniBatchKMeans
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.cluster import v_measure_score
Definir Normalizador Numérico
Definiremos uma função number_normalizer() para mapear todos os tokens numéricos para um marcador de substituição. Isto é usado para redução de dimensionalidade.
def number_normalizer(tokens):
"""Mapear todos os tokens numéricos para um marcador de substituição.
Para muitas aplicações, tokens que começam com um número não são diretamente
úteis, mas o facto de tal token existir pode ser relevante. Aplicando esta forma de redução de dimensionalidade, alguns métodos podem ter um desempenho melhor.
"""
return ("#NUMBER" if token[0].isdigit() else token for token in tokens)
Definir NumberNormalizingVectorizer
Definiremos uma classe NumberNormalizingVectorizer() que herda de TfidfVectorizer() para construir um tokenizador que utiliza a função number_normalizer() definida anteriormente.
class NumberNormalizingVectorizer(TfidfVectorizer):
def build_tokenizer(self):
tokenize = super().build_tokenizer()
return lambda doc: list(number_normalizer(tokenize(doc)))
Carregar e Preparar os Dados
Carregaremos o conjunto de dados dos vinte grupos de notícias e excluiremos a categoria "comp.os.ms-windows.misc". Também definiremos o vetorizador.
categories = [
"alt.atheism",
"comp.graphics",
"comp.sys.ibm.pc.hardware",
"comp.sys.mac.hardware",
"comp.windows.x",
"misc.forsale",
"rec.autos",
"rec.motorcycles",
"rec.sport.baseball",
"rec.sport.hockey",
"sci.crypt",
"sci.electronics",
"sci.med",
"sci.space",
"soc.religion.christian",
"talk.politics.guns",
"talk.politics.mideast",
"talk.politics.misc",
"talk.religion.misc",
]
newsgroups = fetch_20newsgroups(categories=categories)
y_true = newsgroups.target
vectorizer = NumberNormalizingVectorizer(stop_words="english", min_df=5)
Vetorizar Dados
Vetorizaremos os dados usando o vetorizador definido anteriormente.
X = vectorizer.fit_transform(newsgroups.data)
Biclustering usando o Algoritmo de Co-clustering Espectral
Realizaremos o biclustering usando o algoritmo de Co-clustering Espectral definindo o cocluster e ajustando-o aos dados.
cocluster = SpectralCoclustering(
n_clusters=len(categories), svd_method="arpack", random_state=0
)
cocluster.fit(X)
y_cocluster = cocluster.row_labels_
Agrupamento usando MiniBatchKMeans
Agruparemos os dados usando MiniBatchKMeans.
kmeans = MiniBatchKMeans(
n_clusters=len(categories), batch_size=20000, random_state=0, n_init=3
)
y_kmeans = kmeans.fit_predict(X)
Encontrar os Melhores Biclusteres
Encontraremos os melhores biclusteres calculando seu corte normalizado e selecionando os cinco melhores.
feature_names = vectorizer.get_feature_names_out()
document_names = list(newsgroups.target_names[i] for i in newsgroups.target)
def bicluster_ncut(i):
rows, cols = cocluster.get_indices(i)
if not (np.any(rows) and np.any(cols)):
import sys
return sys.float_info.max
row_complement = np.nonzero(np.logical_not(cocluster.rows_[i]))[0]
col_complement = np.nonzero(np.logical_not(cocluster.columns_[i]))[0]
weight = X[rows][:, cols].sum()
cut = X[row_complement][:, cols].sum() + X[rows][:, col_complement].sum()
return cut / weight
bicluster_ncuts = list(bicluster_ncut(i) for i in range(len(newsgroups.target_names)))
best_idx = np.argsort(bicluster_ncuts)[:5]
Imprimir Resultados
Imprimiremos os resultados dos melhores biclusteres encontrados na etapa 8.
for idx, cluster in enumerate(best_idx):
n_rows, n_cols = cocluster.get_shape(cluster)
cluster_docs, cluster_words = cocluster.get_indices(cluster)
if not len(cluster_docs) or not len(cluster_words):
continue
## categorias
counter = defaultdict(int)
for i in cluster_docs:
counter[document_names[i]] += 1
cat_string = ", ".join(
"{:.0f}% {}".format(float(c) / n_rows * 100, name)
for name, c in most_common(counter)[:3]
)
## palavras
out_of_cluster_docs = cocluster.row_labels_ != cluster
out_of_cluster_docs = np.where(out_of_cluster_docs)[0]
word_col = X[:, cluster_words]
word_scores = np.array(
word_col[cluster_docs, :].sum(axis=0)
- word_col[out_of_cluster_docs, :].sum(axis=0)
)
word_scores = word_scores.ravel()
important_words = list(
feature_names[cluster_words[i]] for i in word_scores.argsort()[:-11:-1]
)
print("bicluster {} : {} documentos, {} palavras".format(idx, n_rows, n_cols))
print("categorias : {}".format(cat_string))
print("palavras : {}\n".format(", ".join(important_words)))
Resumo
Neste laboratório, aprendemos como realizar biclustering usando o algoritmo de Co-clustering Espectral no conjunto de dados dos vinte grupos de notícias. Também aprendemos como agrupar os dados usando MiniBatchKMeans para comparação. Finalmente, encontramos os melhores biclusteres calculando seu corte normalizado e selecionando os cinco melhores.