余弦相似性与汉明距离 [闭合]

2022-08-30 22:01:52

为了计算两个文档之间的相似性,我创建了一个包含术语频率的特征向量。但是,对于下一步,我无法在“余弦相似性”和“汉明距离”之间做出决定。

我的问题是:你有这些算法的经验吗?哪一个能给你更好的结果?

除此之外:你能告诉我如何在PHP中编码余弦相似性吗?对于汉明距离,我已经得到了代码:

function check ($terms1, $terms2) {
    $counts1 = array_count_values($terms1);
    $totalScore = 0;
    foreach ($terms2 as $term) {
        if (isset($counts1[$term])) $totalScore += $counts1[$term];
    }
    return $totalScore * 500 / (count($terms1) * count($terms2));
}

我不想使用任何其他算法。我只想得到帮助来决定两者。

也许有人可以谈谈如何改进算法。如果过滤掉停用词或常用词,会得到更好的结果吗?

我希望你能帮助我。提前致谢!


答案 1

汉明距离应该在两个长度相等的字符串之间完成,并考虑顺序。

由于您的文档长度肯定不同,并且如果单词place不算在内,则余弦相似性更好(请注意,根据您的需求,存在更好的解决方案)。:)

下面是 2 个单词数组的余弦相似性函数:

function cosineSimilarity($tokensA, $tokensB)
{
    $a = $b = $c = 0;
    $uniqueTokensA = $uniqueTokensB = array();

    $uniqueMergedTokens = array_unique(array_merge($tokensA, $tokensB));

    foreach ($tokensA as $token) $uniqueTokensA[$token] = 0;
    foreach ($tokensB as $token) $uniqueTokensB[$token] = 0;

    foreach ($uniqueMergedTokens as $token) {
        $x = isset($uniqueTokensA[$token]) ? 1 : 0;
        $y = isset($uniqueTokensB[$token]) ? 1 : 0;
        $a += $x * $y;
        $b += $x;
        $c += $y;
    }
    return $b * $c != 0 ? $a / sqrt($b * $c) : 0;
}

它很快(而不是大型阵列上的杀手)。isset()in_array()

如您所见,结果没有考虑每个单词的“大小”。

我用它来检测“几乎”复制粘贴文本的多发布消息。它运行良好。:)

有关字符串相似性指标的最佳链接http://www.dcs.shef.ac.uk/~sam/stringmetrics.html

有关更多有趣的阅读:

http://www.miislita.com/information-retrieval-tutorial/cosine-similarity-tutorial.html http://bioinformatics.oxfordjournals.org/cgi/content/full/22/18/2298


答案 2

除非我弄错了,否则我认为你的算法介于两种算法之间。对于汉明距离,请使用:

function check ($terms1, $terms2) {
    $counts1 = array_count_values($terms1);
    $totalScore = 0;
    foreach ($terms2 as $term) {
        if (isset($counts1[$term])) $totalScore += 1;
    }
    return $totalScore * 500 / (count($terms1) * count($terms2));
}

(请注意,您只为令牌向量中的每个匹配元素添加 1 个。

对于余弦相似性,请使用:

function check ($terms1, $terms2) {
    $counts1 = array_count_values($terms1);
    $counts2 = array_count_values($terms2);
    $totalScore = 0;
    foreach ($terms2 as $term) {
        if (isset($counts1[$term])) $totalScore += $counts1[$term] * $counts2[$term];
    }
    return $totalScore / (count($terms1) * count($terms2));
}

(请注意,您正在两个文档之间添加令牌计数的乘积。

两者之间的主要区别在于,当两个文档在文档中多次具有相同的单词时,余弦相似性将产生更强的指标,而汉明距离并不关心单个令牌出现的频率

编辑:刚刚注意到您关于删除功能词等的查询。如果你要使用余弦相似性,我确实建议这样做 - 因为函数词非常频繁(至少在英语中),你可能会通过不过滤它们来扭曲结果。如果您使用汉明距离,效果不会那么大,但在某些情况下仍然可能很明显。此外,如果您可以访问词形还原器,例如,当一个文档包含“星系”而另一个文档包含“星系”时,它将减少未命中。

无论你走哪条路,祝你好运!


推荐