Php 余弦相似性与汉明距离
为了计算两个文档之间的相似性,我创建了一个包含术语频率的特征向量。但是,下一步,我无法在“”和“”之间做出决定 我的问题:你有使用这些算法的经验吗?哪一个能给你更好的结果 除此之外:你能告诉我如何在PHP中编码余弦相似性吗?对于汉明距离,我已经得到了代码:Php 余弦相似性与汉明距离,php,relationship,similarity,Php,Relationship,Similarity,为了计算两个文档之间的相似性,我创建了一个包含术语频率的特征向量。但是,下一步,我无法在“”和“”之间做出决定 我的问题:你有使用这些算法的经验吗?哪一个能给你更好的结果 除此之外:你能告诉我如何在PHP中编码余弦相似性吗?对于汉明距离,我已经得到了代码: function check ($terms1, $terms2) { $counts1 = array_count_values($terms1); $totalScore = 0; foreach ($terms2
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?!是否仍然需要将相似度值除以文档长度?此工具用于二进制字符串比较。“我的”函数用于“文字文档”。结果将不一样。:)好的,谢谢。我正在寻找一些工具进行比较,因为我想确保这次我有正确的函数;)并且我不需要将该值除以文档的长度,因为长度不需要