使用Weka的Java文档聚类



我正在尝试聚集一组关于特定主题的Java新闻文章。我使用Crawler4J抓取关于特定主题的新闻站点,将我自己的TF/IDF实现与语料库进行比较(我没有使用内置的Weka或其他TF/IDF实现的原因,但它们可能超出了这个问题的范围),并应用了一些其他领域特定的逻辑,这让我为每个文档保留了一个单词+权重的包(我将其存储在一个值介于0到1之间的Map中)。我想通过查看单词权重来聚类关于类似主题的文章,所以我开始使用Weka的EM和SimpleKMeans聚类器。问题是我得到的结果非常不令人印象深刻,我正在试图弄清楚我是否可以做些什么来更好地调整集群。

例如,在一个有300篇文章的玩具数据集中,如果我将每个文档中的单词修剪到前20个,然后使用完整的单词集作为特征,我最终会得到大约2k个独特的特征。我使用每篇文章作为一个训练实例,并尝试一些不同的参数来调整SimpleKMeans集群(例如~20-30个集群,100个最大迭代)。当我看一眼数据时,我发现很多文章的关键字似乎非常密切相关,所以我期望高质量的结果和一堆包含~5-10篇文章的聚类。不幸的是,结果通常是一个集群有>一半的文章,一堆集群每个有1篇文章,还有一些散乱的集群有2-5篇左右的文章。

这些结果是预期的吗,还是有办法得到更高质量的结果?请注意,我还研究了LingPipe和其他提供集群功能的框架,并尝试了我自己的EM实现(一般但不是很成功)。提前感谢任何帮助!

有几个技巧可以使k-means适用于text:

  1. 删除仅在少数文档中出现的术语(df较低)。这些人为地放大了向量空间中的距离。
  2. 正常化向量。这有点帮助,因为它消除了文档之间的长度差异。正如@ anonymous - mousse所指出的那样,它也使文档向量具有类似的差异。
  3. 在进行实际聚类之前,使用LSA(即截断的SVD)执行降维。这很有帮助。(一定要将LSA的结果也归一化)

规范化工作的简短解释:假设你有三个文档{d₁,d₂,d₃},和一个很小的词汇{cat, dog, tax}。术语-文档矩阵(原始计数或tf-idf,不重要)看起来像

   | cat | dog | tax
d₁ | 100 | 100 |   0
d₂ |  10 |  10 |   0
d₃ |   0 |   0 | 100

现在我们要做双均值。我们可以合理地期望找到一个宠物集群{d₁,d₂}和一个金融单一集群{d₃}。然而,对之间的距离为

D(d₁, d₂) = 127.28
D(d₁, d₃) = 173.21
D(d₂, d₃) = 101.00

所以基于密度的方法,比如k-means,将倾向于把d₂和d₃归为一类。通过规范化向量,你可以有效地将d₁和d₂映射到同一个向量[0.71,0.71,0],因此d (d₁,d₂)= 0,它们将始终在同一个簇中。

(k-应用于归一化向量的means有时被称为"球面"k-means,因为单位向量位于以原点为中心的超球上。)

如果您有一组单词和它们的权重,那么您应该首先计算它们之间的一些相似性度量。例如提花相似度,余弦相似度....然后有了这个基础,你可以使用K-Means或其他聚类算法聚类你的文章。

如果你知道新闻文章只能是固定的类型,如体育,娱乐,历史,政治等,那么我建议你使用分类算法而不是聚类算法,这将增加你获得好的和令人印象深刻的结果的概率。

如果真的想使用聚类算法,可以选择一些可以产生动态聚类的扩展算法(最近邻算法,遗传算法,质量阈值,最小生成树…)。

k-means和EM模型均通过其均值向量聚类,相似度基于欧几里得分布。而距离。

问题在于均值对于稀疏数据可能是不明智的。最能说明这一点的事实是,方法没有文档那么稀疏。此外,甚至可能发生的是,这些手段变得更加相似,而不是实际的文件。

所以恕我直言,你只是对你的数据使用了不合适的聚类算法。有时它可能工作得很好,但有时它会失败,因为该方法是为每个轴上具有相同方差的密集数据而设计的。

最新更新