Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/274.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 余弦相似性与汉明距离_Php_Relationship_Similarity - Fatal编程技术网

Php 余弦相似性与汉明距离

Php 余弦相似性与汉明距离,php,relationship,similarity,Php,Relationship,Similarity,为了计算两个文档之间的相似性,我创建了一个包含术语频率的特征向量。但是,下一步,我无法在“”和“”之间做出决定 我的问题:你有使用这些算法的经验吗?哪一个能给你更好的结果 除此之外:你能告诉我如何在PHP中编码余弦相似性吗?对于汉明距离,我已经得到了代码: function check ($terms1, $terms2) { $counts1 = array_count_values($terms1); $totalScore = 0; foreach ($terms2

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

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

除此之外:你能告诉我如何在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));
}
我不想使用任何其他算法。我只想在两者之间做出选择

也许有人可以对如何改进算法说点什么。如果你过滤掉停止词或常用词,你会得到更好的结果吗


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

我很抱歉忽略了一个事实,你说你不想使用任何其他算法,但说真的,而且比汉明距离更有用。下面是一个例子,如果您不喜欢PHP的原生
levenshtein()
函数,我想您不会喜欢,因为它有长度限制,下面是一个非长度限制的版本:

function levenshtein_distance($text1, $text2) {
    $len1 = strlen($text1);
    $len2 = strlen($text2);
    for($i = 0; $i <= $len1; $i++)
        $distance[$i][0] = $i;
    for($j = 0; $j <= $len2; $j++)
        $distance[0][$j] = $j;
    for($i = 1; $i <= $len1; $i++)
        for($j = 1; $j <= $len2; $j++)
            $distance[$i][$j] = min($distance[$i - 1][$j] + 1, $distance[$i][$j - 1] + 1, $distance[$i - 1][$j - 1] + ($text1[$i - 1] != $text2[$j - 1]));
    return $distance[$len1][$len2];
}
函数levenshtein_距离($text1,$text2){
$len1=strlen($text1);
$len2=strlen($text2);

对于($i=0;$i,除非我弄错了,否则我认为您的算法介于两种算法之间。对于汉明距离,请使用:

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));
}
(请注意,您正在两个文档之间添加令牌计数的乘积。)

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

编辑:刚刚注意到您关于删除虚词等的查询。如果您打算使用余弦相似性,我建议您这样做,因为虚词非常常见(至少在英语中),您可能会通过不过滤它们来扭曲结果。如果您使用汉明距离,效果不会太大,但在某些情况下仍然可以感知。此外,如果您可以访问,例如,当一个文档包含“星系”,而另一个文档包含“星系”时,它将减少未命中


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

在两条长度相等的弦之间,都应该做一个汉明距离,并考虑顺序

由于您的文档长度不同,如果单词places不算在内,那么余弦相似性更好(请注意,根据您的需要,存在更好的解决方案)。:)

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

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()
而不是
在数组中()
是大型数组的杀手)

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

我用它来检测“几乎”复制粘贴文本的多条发布消息。效果很好。:)

关于字符串相似性度量的最佳链接

更多有趣的阅读:


这里是Toto发布的修正后的余弦距离函数代码

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 += pow($x,2);
        $c += pow($y,2);
    }
    return $b * $c != 0 ? $a / sqrt($b * $c) : 0;
}

谢谢。我想你误解了一些东西。我不想只使用汉明距离。我想将它应用到文本的特征向量,而不是文本本身。所以我想说它比levenshtein更有用,不是吗?;)但是谢谢你的代码,我确信它对许多用户的其他用途有用。哎呀,我没有做到吸收特征向量部分。没关系。:)既然你喜欢这个代码,我就不删除答案。我希望下层选民会仁慈。:)是的,他们有。上层选民比下层选民多。;)levenshtein应该用来计算编辑距离。所以这取决于需要。“ANNA FRED”和“FRED ANNA”.Lenvenshtein将给出一个很高的数字,但对于余弦相似性(对于单词)它将是100%相似。相似与否?这取决于你的需要。非常感谢!所以如果我使用两种算法的组合,它是否也结合了它们的优点?比这两种算法更好,对吗?:)或者我应该更好地使用你的代码示例吗?你的最后一句话很有趣。所以余弦相似性就我的目的而言,这会更好,对吗?因为如果一个词经常出现,两个文本之间的关系会更强,不是吗?@marco92w:我认为余弦相似性在这种情况下是最好的-也可以看看我最近编辑的关于虚词的文章。你的直觉就在这里。Thx,编辑也是信息性的。最后一个问题::)两者之间的区别是什么即使是余弦相似性和我的算法(有问题的代码)?哪一个更好?这个余弦相似性函数中有一些奇怪的东西。在这种情况下,结果不应该是1:回声检查(数组('a','b','c'),数组('a','b','c'));相反,我得到的结果是0.333,顺便说一句,它与:回声检查(数组('a','b','c'),数组('a','b'));Toto是正确的。两个距离函数的向量范数计算都不正确。非常感谢。:)但是Mike的解决方案(选择的答案)不是更好吗?代码更短,似乎和您的一样快。有什么区别吗?Mike的函数不是很精确。请尝试
回声检查(数组('a','b','c'),数组('a','b','c'));
它应该返回1(cos(0)),但他的函数返回0.33.:(你的函数真的正确吗?它对[1,1,1]和[1,1,0]给出了0.71%。但是给出了0.82?!是否仍然需要将相似度值除以文档长度?此工具用于二进制字符串比较。“我的”函数用于“文字文档”。结果将不一样。:)好的,谢谢。我正在寻找一些工具进行比较,因为我想确保这次我有正确的函数;)并且我不需要将该值除以文档的长度,因为长度不需要