如何使用 k-means (Flann with python) 对文档进行聚类?
Posted
技术标签:
【中文标题】如何使用 k-means (Flann with python) 对文档进行聚类?【英文标题】:How can i cluster document using k-means (Flann with python)? 【发布时间】:2012-09-11 21:53:13 【问题描述】:我想根据相似性对文档进行聚类。
我已经尝试过 ssdeep(相似性哈希),速度非常快,但有人告诉我 k-means 更快,而 flann 是所有实现中最快的,而且更准确,所以我正在尝试使用 python 绑定的 flann,但我找不到任何示例如何在文本上执行(它只支持数字数组)。
我对这个领域非常陌生(k-means,自然语言处理)。我需要的是速度和准确性。
我的问题是:
-
我们能否使用 KMeans 进行文档相似性分组/聚类(Flann 似乎不允许任何文本输入)
Flann 是正确的选择吗?如果不是,请向我推荐支持文本/文档集群的高性能库,它具有 python 包装器/API。
k-means 算法是否正确?
【问题讨论】:
这与***.com/questions/8057442/document-clustering-basics 的问题几乎相同。我建议您查看 scikit-learn,它具有您需要的大部分内置功能,并且具有很好的可扩展性:scikit-learn.org/stable/auto_examples/document_clustering.html。或者,NLTK 也有 k-means:nltk.org/_modules/nltk/cluster/kmeans.html。 非常感谢。 scikit vs nltk 性能如何,你能评论一下吗? 我从未尝试过 NLTK 的聚类,但可以肯定的是,对于大型数据集,scikit-learn 的速度会快几个数量级。不过,NLTK 可能更易于使用。 如果您需要进行近似 k-NN 查询,那么 FLANN 是最先进的(据我所知,scikit-learn 和 NLTK 中没有近似 k-NN 查询模块)。但是 k-NN 查询和 K-Means 聚类并不能解决同一个问题。 【参考方案1】:您需要将文档表示为数字数组(又名向量)。有很多方法可以做到这一点,具体取决于您想要的复杂程度,但最简单的方法就是将其表示为字数的向量。
所以这就是你要做的:
统计每个单词在文档中出现的次数。
选择一组将包含在向量中的“特征”词。这应该排除非常常见的词(又名“停用词”),例如“the”、“a”等。
根据特征词的计数为每个文档制作一个向量。
这是一个例子。
如果您的“文档”是单个句子,并且它们看起来像(每行一个文档):
there is a dog who chased a cat
someone ate pizza for lunch
the dog and a cat walk down the street toward another dog
如果我的特征词集是[dog, cat, street, pizza, lunch]
,那么我可以将每个文档转换成一个向量:
[1, 1, 0, 0, 0] // dog 1 time, cat 1 time
[0, 0, 0, 1, 1] // pizza 1 time, lunch 1 time
[2, 1, 1, 0, 0] // dog 2 times, cat 1 time, street 1 time
您可以在您的 k-means 算法中使用这些向量,它有望将第一个和第三个句子组合在一起,因为它们很相似,并让第二个句子成为一个单独的集群,因为它非常不同。
【讨论】:
非常有趣,几天前我在某处读到 scikit.learn 具有矢量化任何文本文件或字符串的功能。我想知道它给出的数据结构是否适合 Flann? 我只想补充一点,您可以使用一些词干算法来确保您将同一个词的小变体视为同一个关键字。这将减少变量的数量,并使整个过程更加准确。有关更多信息,请参阅此链接link 是的,那很好,我可以使用 NLTK 来生成/标记单词。 如果我没有任何特征词并且我的词袋只是“任何不是停用词的词”,那么每个向量都是所有可能词的长度,每个索引代表分配给该指数的词? @Carpetfizz。没错。【参考方案2】:这里有个大问题:
K-means 是为欧几里得距离设计的。
关键问题是均值函数。均值将减少欧几里得距离的方差,但对于不同的距离函数可能不会这样做。所以在最坏的情况下,k-means 将不再收敛,而是在无限循环中运行(尽管大多数实现都支持在最大迭代次数处停止)。
此外,对于 sparse 数据,均值不是很合理,而文本向量往往是 very 稀疏的。粗略地说,问题在于大量文档的 mean 将不再看起来像真实文档,并且这种方式变得与任何真实文档不同,而与其他均值向量更相似。所以结果在一定程度上退化了。
对于文本向量,您可能需要使用不同的距离函数,例如余弦相似度。
当然,您首先需要计算数字向量。例如,通过使用相对词频,通过 TF-IDF 对其进行归一化。
k-means 有一个变体,称为 k-medoids。它可以使用任意距离函数,并且通过使用对集群最核心的 real 文档(“medoid”)来避免整个“平均”的事情。但是这方面的已知算法比 k-means 慢得多。
【讨论】:
非常感谢您指出这一点。您推荐的任何 K-medoids 实现?以上是关于如何使用 k-means (Flann with python) 对文档进行聚类?的主要内容,如果未能解决你的问题,请参考以下文章
K-Means clusternig example with Python and Scikit-learn(推荐)
Extending sparklyr to Compute Cost for K-means on YARN Cluster with Spark ML Library