Algorithm 最佳聚类算法?(简单解释)

Algorithm 最佳聚类算法?(简单解释),algorithm,text,cluster-analysis,data-mining,text-mining,Algorithm,Text,Cluster Analysis,Data Mining,Text Mining,想象一下以下问题: 你有一个数据库,在一个名为“articles”的表格中包含大约20000个文本 您希望使用集群算法连接相关文章,以便将相关文章显示在一起 算法应该进行平面聚类(而不是分层) 相关条款应插入“相关”表中 聚类算法应该根据文本决定两篇或更多文章是否相关 我想用PHP编写代码,但是用伪代码或其他编程语言编写的示例也可以 我已经用函数check()编写了初稿,如果两个输入项目相关,则给出“true”,否则给出“false”。代码的其余部分(从数据库中选择文章、选择要比较的文章、插

想象一下以下问题:

  • 你有一个数据库,在一个名为“articles”的表格中包含大约20000个文本
  • 您希望使用集群算法连接相关文章,以便将相关文章显示在一起
  • 算法应该进行平面聚类(而不是分层)
  • 相关条款应插入“相关”表中
  • 聚类算法应该根据文本决定两篇或更多文章是否相关
  • 我想用PHP编写代码,但是用伪代码或其他编程语言编写的示例也可以
我已经用函数check()编写了初稿,如果两个输入项目相关,则给出“true”,否则给出“false”。代码的其余部分(从数据库中选择文章、选择要比较的文章、插入相关文章)也已完成。也许你还可以改进其他的。但对我来说重要的一点是函数check()。所以,如果你能发布一些改进或完全不同的方法,那就太好了

方法1

<?php
$zeit = time();
function check($str1, $str2){
    $minprozent = 60;
    similar_text($str1, $str2, $prozent);
    $prozent = sprintf("%01.2f", $prozent);
    if ($prozent > $minprozent) {
        return TRUE;
    }
    else {
        return FALSE;
    }
}
$sql1 = "SELECT id, text FROM articles ORDER BY RAND() LIMIT 0, 20";
$sql2 = mysql_query($sql1);
while ($sql3 = mysql_fetch_assoc($sql2)) {
    $rel1 = "SELECT id, text, MATCH (text) AGAINST ('".$sql3['text']."') AS score FROM articles WHERE MATCH (text) AGAINST ('".$sql3['text']."') AND id NOT LIKE ".$sql3['id']." LIMIT 0, 20";
    $rel2 = mysql_query($rel1);
    $rel2a = mysql_num_rows($rel2);
    if ($rel2a > 0) {
        while ($rel3 = mysql_fetch_assoc($rel2)) {
            if (check($sql3['text'], $rel3['text']) == TRUE) {
                $id_a = $sql3['id'];
                $id_b = $rel3['id'];
                $rein1 = "INSERT INTO related (article1, article2) VALUES ('".$id_a."', '".$id_b."')";
                $rein2 = mysql_query($rein1);
                $rein3 = "INSERT INTO related (article1, article2) VALUES ('".$id_b."', '".$id_a."')";
                $rein4 = mysql_query($rein3);
            }
        }
    }
}
?>

我所知道的对文本数据执行此操作的最标准方法是使用“文字袋”技术

首先,为每篇文章创建一个单词的“直方图”。假设在你所有的文章之间,你只有500个独特的单词。然后这个直方图将是一个大小为500的向量(数组、列表等等),其中的数据是每个单词在文章中出现的次数。因此,如果向量中的第一个点表示单词“ask”,并且该单词在文章中出现了5次,那么向量[0]将是5:

for word in article.text
    article.histogram[indexLookup[word]]++
现在,要比较任何两篇文章,都非常简单。我们只需将两个向量相乘:

def check(articleA, articleB)
    rtn = 0
    for a,b in zip(articleA.histogram, articleB.histogram)
        rtn += a*b
    return rtn > threshold
(很抱歉使用python而不是PHP,我的PHP已经过时了,使用zip使这一点变得更容易了)

这是基本思想。注意阈值是半任意的;你可能想找到一个很好的方法来规范你的直方图的点积(这几乎必须在文章长度的某个因素),并决定你认为“相关”。p> 此外,你不应该把每个单词都放进你的直方图中。一般来说,您会希望包含半频繁使用的内容:不是在每一篇文章中,也不是只在一篇文章中。这会在柱状图上节省一点开销,并增加关系的价值


顺便说一句,这项技术被更详细地描述了

方法1中调用的
类似文本
函数是什么样子的?我想你指的不是聚类,而是相似性度量。我真的无法改进White Walloun的:-)直方图方法——这是一个值得阅读的有趣问题

无论您如何实现
check()
,您都必须使用它进行至少2亿次比较(20000^2
的一半)。“相关”文章的截止可能会限制您在数据库中存储的内容,但似乎过于武断,无法捕获所有有用的文本聚类


我的方法是修改
check()
以返回“相似性”度量(
$prozent
rtn
)。将
20K x 20K
矩阵写入一个文件,并使用外部程序执行聚类,以确定每篇文章的最近邻,您可以将其加载到
相关的
表中。我会在
R
中进行聚类-从
php

运行
R
的文件中对数据进行聚类有一个很好的方法,我相信您需要做出一些关于聚类的设计决策,并从那里继续:

  • 你为什么对文本进行聚类?是否要同时显示相关文档?您想通过集群浏览文档语料库吗
  • 因此,您是否希望使用集群
  • 现在我们有两个方面的复杂性问题:首先,你从文本中创建的特征的数量和类型——单个单词的数量可能有几万个。你可能想尝试一些方法,比如取信息量最大的N个单词,或者忽略后出现次数最多的N个单词
  • 其次,您希望最小化度量文档之间相似性的次数。正如bubaker正确指出的,检查所有文档对之间的相似性可能太多了。如果聚类成少量的集群是足够的,你可以考虑,基本上是:选择初始K文档作为聚类中心,将每个文档分配到最接近的簇,通过找到文档向量均值来重新计算聚类中心,并迭代。每次迭代只需花费K*个文档。我相信还有一些启发式方法可以减少分层聚类所需的计算量
    也许集群是错误的策略

    如果要显示相似的文章,请改用相似性搜索

    对于文本文章,这是很好理解的。只需将您的文章插入文本搜索数据库(如Lucene),并使用您当前的文章作为搜索查询。在Lucene中,有一种方法可以实现这一点:查找类似的文章

    集群是一个错误的工具,因为(特别是根据您的需求),每一篇文章都必须放在某个集群中;集群中的每个对象的相关项都是相同的。如果数据库中存在异常值(很可能是这种情况),它们可能会破坏您的集群。此外,集群可能非常大。没有大小限制,聚类算法可能会决定将数据集的一半放入同一个集群。因此,数据库中的每一篇文章都有10000篇相关文章。使用相似性搜索,您只需为每个文档获取前10个相似项

    最后但并非最不重要的一点:忘记PHP用于集群。它不是为这个而设计的,性能也不够。但是你可以
    def check(articleA, articleB)
        rtn = 0
        for a,b in zip(articleA.histogram, articleB.histogram)
            rtn += a*b
        return rtn > threshold