在处理文本数据时,共聚类算法能够同时对文档和词汇进行分组,以便发现文档子集和词汇子集之间的关联。本文将介绍如何将这种算法应用于著名的新闻组数据集,并且排除了'comp.os.ms-windows.misc'类别,因为该类别中的许多帖子只包含数据而不包含实际的文本内容。
首先,使用TF-IDF方法将帖子向量化,形成一个词频矩阵。然后,利用Dhillon的谱共聚类算法对这个词频矩阵进行双聚类。通过这种方法,能够识别出在特定文档子集中更频繁使用的词汇子集。
对于找到的最佳双聚类,打印出最常见的文档类别和最重要的十个词汇。最佳双聚类是根据它们的归一化割裂度来确定的,而最佳词汇则是通过比较它们在双聚类内外的总和来确定的。
为了进行比较,还使用MiniBatchKMeans算法对文档进行了聚类。从双聚类派生的文档聚类比MiniBatchKMeans找到的聚类具有更好的V-measure值。
在执行向量化和共聚类之后,得到了以下结果:
Vectorizing...
Coclustering...
Done in 1.14s. V-measure: 0.4415
MiniBatchKMeans...
Done in 2.16s. V-measure: 0.3015
以下是一些最佳的双聚类示例:
双聚类 0: 包含8个文档,6个词汇 类别: 100% talk.politics.mideast 词汇: cosmo, angmar, alfalfa, alphalpha, proline, benson
双聚类 1: 包含1948个文档,4325个词汇 类别: 23% talk.politics.guns, 18% talk.politics.misc, 17% sci.med 词汇: gun, guns, geb, banks, gordon, clinton, pitt, cdt, surrender, veal
双聚类 2: 包含1259个文档,3534个词汇 类别: 27% soc.religion.christian, 25% talk.politics.mideast, 25% alt.atheism 词汇: god, jesus, christians, kent, sin, objective, belief, christ, faith, moral
双聚类 3: 包含775个文档,1623个词汇 类别: 30% comp.windows.x, 25% comp.sys.ibm.pc.hardware, 20% comp.graphics 词汇: scsi, nada, ide, vga, esdi, isa, kth, s3, vlb, bmug
双聚类 4: 包含2180个文档,2802个词汇 类别: 18% comp.sys.mac.hardware, 16% sci.electronics, 16% comp.sys.ibm.pc.hardware 词汇: voltage, shipping, circuit, receiver, processing, scope, mpce, analog, kolstad, umass
在代码实现方面,首先导入了必要的库,包括用于处理集合的defaultdict,用于记录时间的time,以及用于数值计算的numpy。还导入了机器学习库sklearn中的MiniBatchKMeans和SpectralCoclustering,以及用于数据集加载的fetch_20newsgroups,用于文本特征提取的TfidfVectorizer,以及用于聚类评估的v_measure_score。
import operator
from collections import defaultdict
from time import time
import numpy as np
from sklearn.cluster import MiniBatchKMeans, SpectralCoclustering
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。这个类重写了build_tokenizer方法,以便在对文档进行标记化时应用number_normalizer函数。
class NumberNormalizingVectorizer(TfidfVectorizer):
def build_tokenizer(self):
tokenize = super().build_tokenizer()
return lambda doc: list(number_normalizer(tokenize(doc)))
在确定了要使用的类别后,使用fetch_20newsgroups函数加载新闻组数据。然后,创建了一个NumberNormalizingVectorizer实例和一个SpectralCoclustering实例,用于后续的向量化和共聚类操作。还创建了一个MiniBatchKMeans实例,用于比较聚类效果。
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)
cocluster = SpectralCoclustering(n_clusters=len(categories), svd_method="arpack", random_state=0)
kmeans = MiniBatchKMeans(n_clusters=len(categories), batch_size=20000, random_state=0, n_init=3)
在向量化和共聚类过程中,记录了所需的时间,并计算了V-measure值来评估聚类效果。还定义了bicluster_ncut函数来计算每个双聚类的归一化割裂度,并找到了最佳的五个双聚类。
print("Vectorizing...")
X = vectorizer.fit_transform(newsgroups.data)
print("Coclustering...")
start_time = time()
cocluster.fit(X)
y_cocluster = cocluster.row_labels_
print("Done in {:.2f} s. V-measure: {:.4f}".format(time() - start_time, v_measure_score(y_cocluster, y_true)))