使用谱共聚类算法进行文档双聚类

Machine LearningMachine LearningBeginner
立即练习

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

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,我们将对20个新闻组数据集使用谱共聚类(Spectral Co-clustering)算法对文档进行双聚类。该数据集包含20类文档,我们将排除“comp.os.ms-windows.misc”类别,因为其中包含无数据的帖子。经TF-IDF矢量化后的帖子形成一个词频矩阵,然后使用迪隆(Dhillon)的谱共聚类算法对其进行双聚类。得到的文档-词双聚类表示在那些文档子集中更常使用的词的子集。我们还将使用MiniBatchKMeans对文档进行聚类以作比较。

虚拟机使用提示

虚拟机启动完成后,点击左上角切换到“笔记本”(Notebook)标签页,以访问Jupyter Notebook进行练习。

有时,你可能需要等待几秒钟让Jupyter Notebook完成加载。由于Jupyter Notebook的限制,操作验证无法自动化。

如果你在学习过程中遇到问题,随时向Labby提问。课程结束后提供反馈,我们将迅速为你解决问题。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL ml(("Machine Learning")) -.-> ml/FrameworkandSoftwareGroup(["Framework and Software"]) sklearn(("Sklearn")) -.-> sklearn/CoreModelsandAlgorithmsGroup(["Core Models and Algorithms"]) sklearn(("Sklearn")) -.-> sklearn/DataPreprocessingandFeatureEngineeringGroup(["Data Preprocessing and Feature Engineering"]) sklearn(("Sklearn")) -.-> sklearn/ModelSelectionandEvaluationGroup(["Model Selection and Evaluation"]) sklearn(("Sklearn")) -.-> sklearn/UtilitiesandDatasetsGroup(["Utilities and Datasets"]) sklearn/CoreModelsandAlgorithmsGroup -.-> sklearn/cluster("Clustering") sklearn/DataPreprocessingandFeatureEngineeringGroup -.-> sklearn/feature_extraction("Feature Extraction") sklearn/ModelSelectionandEvaluationGroup -.-> sklearn/metrics("Metrics") sklearn/UtilitiesandDatasetsGroup -.-> sklearn/datasets("Datasets") ml/FrameworkandSoftwareGroup -.-> ml/sklearn("scikit-learn") subgraph Lab Skills sklearn/cluster -.-> lab-49069{{"使用谱共聚类算法进行文档双聚类"}} sklearn/feature_extraction -.-> lab-49069{{"使用谱共聚类算法进行文档双聚类"}} sklearn/metrics -.-> lab-49069{{"使用谱共聚类算法进行文档双聚类"}} sklearn/datasets -.-> lab-49069{{"使用谱共聚类算法进行文档双聚类"}} ml/sklearn -.-> lab-49069{{"使用谱共聚类算法进行文档双聚类"}} end

导入库

我们将为本实验导入必要的库。

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

定义数字归一化器

我们将定义一个函数 number_normalizer(),用于将所有数字标记映射到一个占位符。这用于降维。

def number_normalizer(tokens):
    """将所有数字标记映射到一个占位符。

    对于许多应用来说,以数字开头的标记并不直接有用,但这样的标记存在这一事实可能是相关的。通过应用这种形式的降维,一些方法可能会表现得更好。
    """
    return ("#NUMBER" if token[0].isdigit() else token for token in tokens)

定义数字归一化矢量化器

我们将定义一个类 NumberNormalizingVectorizer(),它继承自 TfidfVectorizer(),以构建一个使用我们之前定义的 number_normalizer() 函数的分词器。

class NumberNormalizingVectorizer(TfidfVectorizer):
    def build_tokenizer(self):
        tokenize = super().build_tokenizer()
        return lambda doc: list(number_normalizer(tokenize(doc)))

加载并准备数据

我们将加载20个新闻组数据集,并排除“comp.os.ms-windows.misc”类别。我们还将定义矢量化器。

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)

对数据进行矢量化

我们将使用之前定义的矢量化器对数据进行矢量化。

X = vectorizer.fit_transform(newsgroups.data)

使用谱共聚类算法进行双聚类

我们将通过定义共聚类并将其拟合到数据上来使用谱共聚类算法执行双聚类。

cocluster = SpectralCoclustering(
    n_clusters=len(categories), svd_method="arpack", random_state=0
)
cocluster.fit(X)
y_cocluster = cocluster.row_labels_

使用MiniBatchKMeans进行聚类

我们将使用MiniBatchKMeans对数据进行聚类。

kmeans = MiniBatchKMeans(
    n_clusters=len(categories), batch_size=20000, random_state=0, n_init=3
)
y_kmeans = kmeans.fit_predict(X)

寻找最佳双聚类

我们将通过计算双聚类的归一化割并选择排名前五的来找到最佳双聚类。

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]

打印结果

我们将打印在步骤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

    ## 类别
    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]
    )

    ## 单词
    不在聚类中的文档 = cocluster.row_labels_!= cluster
    不在聚类中的文档 = np.where(不在聚类中的文档)[0]
    单词列 = X[:, cluster_words]
    单词得分 = np.array(
        单词列[cluster_docs, :].sum(axis=0)
        - 单词列[不在聚类中的文档, :].sum(axis=0)
    )
    单词得分 = 单词得分.ravel()
    重要单词 = list(
        feature_names[cluster_words[i]] for i in word_scores.argsort()[:-11:-1]
    )

    print("双聚类 {} : {} 个文档, {} 个单词".format(idx, n_rows, n_cols))
    print("类别   : {}".format(cat_string))
    print("单词   : {}\n".format(", ".join(重要单词)))

总结

在本实验中,我们学习了如何在二十个新闻组数据集上使用谱共聚类算法进行双聚类。我们还学习了如何使用MiniBatchKMeans对数据进行聚类以作比较。最后,我们通过计算归一化割并选择排名前五的来找到最佳双聚类。