Biclustering de Documentos Usando o Algoritmo de Co-Clustering Espectral

Beginner

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

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.