返回介绍

3.3 聚类

发布于 2024-01-30 22:34:09 字数 5783 浏览 0 评论 0 收藏 0

最后,我们得到了特征向量,我们相信它足以捕捉到帖子的特征。有很多方法可以把帖子聚合分组,这并不奇怪。多数聚类算法都属于下面两个方法之一:扁平和层次聚类。

扁平聚类会将帖子分成一系列相互之间没有关联的簇。它的目标是通过一个划分,使一个簇中的帖子相互之间非常相似,而所有不同簇中的帖子很不相似。很多扁平聚类算法需要预先指定簇的个数。

在层次聚类中,并不需要指定簇的个数。相反,层次聚类可以构造出簇之间的层次关系。在相似帖子类聚到一个簇中的同时,相似的簇将会进一步聚到一个超级簇中。这个步骤递归下去,直到只剩下一个簇,它包含了所有东西。在层次结构中,人们可以选择所需要的簇的个数。但这样会降低效率。

Scikit在sklearn.cluster 包中提供了范围广泛的聚类方法。你可以在http://scikit-learn.org/dev/modules/clustering.html 快速浏览它们的优缺点。

接下来,我们将会使用扁平聚类方法K均值,并试验一下所需的簇个数。

3.3.1 K均值

K均值是应用最广泛的一个扁平聚类算法。当使用所需的簇个数num_clusters 进行初始化之后,该算法把这个值作为簇质心的数目。起初,它选出任意num_clusters 个帖子,并将它们的特征向量作为这些簇的质心。然后它遍历其他所有帖子,并将离它们最近的质心所在的簇分配给它们。再次,它将每个质心移向该簇中所有特征向量的中心点。当然,这将会改变簇的分配。一些帖子现在距离另一个簇更近了。因此该算法将会更新这些帖子的簇分配。只要质心移动相当一段距离,就可以做到这一点。经过一定的迭代,当移动量低于一定阈值的时候,我们就认为聚类已经收敛了。

提示  下载示例代码
如果你是通过 http://www.packtpub.com 的注册账户购买的图书,你可以从该账户中下载你购买过的所有Packt图书的示例代码。如果你是从其他地方购买的本书,你可以访问 http://www.packtpub.com/support 并进行注册,我们将会给你发送一封附有示例代码文件的电子邮件。

让我们通过一个简单的例子来验证这个算法,这个例子包含只有两个词语的帖子。下图中的每个数据点都代表了一个文档:

经过一次K均值迭代之后,以任意两个向量作为起始点,将标签赋予余下的样本,然后更新簇的中心,使之成为该簇中所有数据点的中心点,我们得到以下聚类:

由于簇中心的移动,我们必须重新分配簇的标签,并重新计算簇的中心点。在第二轮迭代之后,得到以下聚类:

箭头显示了簇中心的移动。在这个例子中,经过5轮迭代,簇中心点不再显著移动(Scikit的默认容许阈值是0.000 1)。

在聚类停当之后,我们只需要记录下簇中心及其标识。当每个新文档进来的时候,我们对它进行向量化,并与所有的簇中心进行比较。我们得到与新帖向量距离最小的簇中心所在的簇,然后把这个簇分配给该新帖子。

3.3.2 让测试数据评估我们的想法

为了测试聚类效果,让我们抛开这个简单的文本示例,寻找一个可以模拟所期待的能够测试我们方法的数据集。为此,我们需要一些已经类聚好的关于技术话题的文档。这样,之后我们在得到的帖子上应用算法时,就可以检验算法的效果是否符合预期。

20newsgroup 数据集是机器学习中的一个标准数据集。它包含18 286个帖子,来自于20个不同的新闻组。在这些新闻组的话题中,有的是技术话题,如comp.sys.mac.hardware 或sci.crypt ,有的是政治话题或和宗教相关话题,如talk.politics.guns 或soc.religion.christian 。我们把范围限制在技术话题的新闻组中。如果我们假定每个新闻组是一个簇,那么很容易测试出我们寻找相关帖子的方法是否有效。

这个数据集可以从http://people.csail.mit.edu/jrennie/20Newsgroups 下载。而更简单的方式是从MLComp(http://mlcomp.org/datasets/379 )下载(需要免费注册)。Scikit已经包含了定制的读取器来读取这个数据集,并提供了非常方便的读取选项。

这个数据集是用ZIP文件形式存放的:dataset-379-20news-18828_WJQIG.zip。我们需要解压得到文件夹379,它包含这个数据集。我们还要告诉Scikit数据目录的路径。它包含一个原信息文件和3个目录:test、train和raw。测试和训练目录将整个数据集切分成60%的训练和40%的测试帖子。为方便起见,dataset 模块还包含了函数fetch_20newsgroups ,它将数据下载到预期目录中。

注意  http://mlcomp.org 是一个用于在多种数据集上比较机器学习算法程序的网站。它有两个目的:找到正确的数据集来调优机器学习程序,以及探究其他人如何使用某个特定的数据集。例如,你可以看到他人的算法在特定数据集上的效果,并与之比较。

在读取数据集的时候,可以设置环境变量MLCOMP_DATASETS_HOME ,或者通过mlcomp_root 参数直接指定路径,如下所示:

>>> import sklearn.datasets
>>> MLCOMP_DIR = r"D:\data"
>>> data = sklearn.datasets.load_mlcomp("20news-18828", mlcomp_
root=MLCOMP_DIR)
>>> print(data.filenames)
array(['D:\\data\\379\\raw\\comp.graphics\\1190-38614',
'D:\\data\\379\\raw\\comp.graphics\\1383-38616',
'D:\\data\\379\\raw\\alt.atheism\\487-53344',
...,
'D:\\data\\379\\raw\\rec.sport.hockey\\10215-54303',
'D:\\data\\379\\raw\\sci.crypt\\10799-15660',
'D:\\data\\379\\raw\\comp.os.ms-windows.misc\\2732-10871'],
dtype='|S68')
>>> print(len(data.filenames))
18828
>>> data.target_names
['alt.atheism', 'comp.graphics', 'comp.os.ms-windows.misc', '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.

我们可以在训练和测试集合中进行选取,如下所示:

>>> train_data = sklearn.datasets.load_mlcomp("20news-18828", "train",
mlcomp_root=MLCOMP_DIR)
>>> print(len(train_data.filenames))
13180
>>> test_data = sklearn.datasets.load_mlcomp("20news-18828",
"test", mlcomp_root=MLCOMP_DIR)
>>> print(len(test_data.filenames))
5648

为方便起见,我们把范围限制在某些新闻组中,使整个实验流程更短。我们可以通过categories 参数实现这一点:

>>> groups = ['comp.graphics', 'comp.os.ms-windows.misc', 'comp.sys.
ibm.pc.hardware', 'comp.sys.ma c.hardware', 'comp.windows.x', 'sci.
space']
>>> train_data = sklearn.datasets.load_mlcomp("20news-18828", "train",
mlcomp_root=MLCOMP_DIR, categories=groups)
>>> print(len(train_data.filenames))
3414

3.3.3 对帖子聚类

你肯定已经注意到了一件事——真实数据含有很多噪声。新闻组数据也不例外。它甚至包含了不合法的字符,这会导致UnicodeDecodeError 。

我们必须要让向量化处理器忽略它们:

>>> vectorizer = StemmedTfidfVectorizer(min_df=10, max_df=0.5,
... stop_words='english', charset_error='ignore')
>>> vectorized = vectorizer.fit_transform(dataset.data)
>>> num_samples, num_features = vectorized.shape
>>> print("#samples: %d, #features: %d" % (num_samples, num_features))
#samples: 3414, #features: 4331

我们现在有一个大小为3414的帖子池,每个帖子的特征向量的维度是4331。这些就是K均值算法的输入。本章中我们把簇的大小固定在50。希望你可以带着好奇心去尝试不同的值,把它当做一个练习。如下列代码所示:

>>> num_clusters = 50
>>> from sklearn.cluster import KMeans
>>> km = KMeans(n_clusters=num_clusters, init='random', n_init=1,
verbose=1)
>>> km.fit(vectorized)

就是这样。在拟合之后,我们可以从km 的成员变量中获得聚类信息。针对每个拟合过的帖子向量,km.labels_ 都给出了一个对应的整数标签:

>>> km.labels_
array([33, 22, 17, ..., 14, 11, 39])
>>> km.labels_.shape
(3414,)

簇的中心可以通过km.cluster_centers_ 访问。

在下一节中我们将会学习如何通过km.predict 给新来的帖子分配一个簇。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文