1

所以我正在将旧的数据可视化转换为新平台,我有点卡在他们的社区排序功能上。在原始代码中,作者似乎使用了带有余弦相似度计算器的凝聚聚类。我认为在 Javascript 中解决此问题的最佳方法是使用我的自定义余弦相似度函数作为指标,使用 clusterfck 制作一棵树。对于我传递的每组数据,树几乎正确地排序。(但由于项目规范,“几乎”还不够好)。我检查了我的算法,一切看起来都正确,但是当我使用余弦相似度和欧几里得距离比较我的结果时,我得到了相同的排序结果。

这可能是什么原因造成的?我想我可能错误地传递了一些东西,而 clusterfck 将欧几里得作为默认值传递。下面是我的一段代码。有人可以验证吗?(另外,有没有更简单的方法来计算余弦相似度?我认为 JS 没有内置的点积)。

clusters = clusterfck.hcluster(relationArray, clusterfck.cosSim2, clusterfck.SINGLE_LINKAGE);
postOrder(clusters);
function postOrder(t) {
i++;
if (t == null) {
    return;
} else {
    postOrder(t.left);
    postOrder(t.right);
    if (t.left == null && t.right == null) {
        communityArr.push(t.canonical[0]);
    } else {
        return;
    }
}
}

function cosSim2(arr1, arr2) {
var d1 = 0,
    d2 = 0,
    cos = 0;
for(var i = 0; i < arr1.length; i++) {
    d1 += Math.pow(arr1[i], 2);
}

for(var j = 0; j < arr2.length; j++) {
    d2 += Math.pow(arr2[j], 2);
}

d1 = Math.sqrt(d1);
d2 = Math.sqrt(d2);

for(var j = 0; j < arr2.length; j++) {
    if (arr1[j] == null) {
        cos += 0;
    } else {
        cos += arr1[j] * arr2[j];
    }
}
var cosSimilarity = cos / (d1 * d2);
return cosSimilarity;
}
4

1 回答 1

3

我想这个回复对你来说太晚了。但万一其他人偶然发现:

问题是您clusterfck.hcluster使用参数clusterfck.cosSim2作为距离度量进行调用。但是由于您的真实距离函数很简单cosSim2,因此您可以clusterfck.hcluster使用未定义的距离函数有效地调用,并且 clusterfck 使用默认的距离函数,即“欧几里得”......

另请注意,您的函数确实测量了向量之间的相似性,而不是它们的距离。即:余弦相似度越大,向量越相似(即它们之间的夹角越小)。

clusterfck.hcluster需要一个真正的距离测量。也就是说,相反的情况应该是正确的:距离度量的值越大,向量越远(即,向量越不相似)。

使用您的函数调用clusterfck.hcluster将产生效果,即最不相似的项目聚集在一起。

您可以轻松地从余弦相似度函数导出距离函数,如下所示:

function cosDist(arr1, arr2) {
    return 1 - cosSim2(arr1, arr2);
}

这个新函数cosDist的值范围为 0 到 2,相同向量的距离为 0(如预期),最远(即不相似)的向量的距离为 2。

另一个注意事项:维基百科文章http://en.wikipedia.org/wiki/Cosine_similarity指出这个 cosDist 在数学意义上不是一个适当的距离度量(三角不等式通常在这里不成立)但根据我的经验在使用此函数进行层次聚类时,在实践中不是问题。它经常以这种方式使用。尽管如此,还是有一种方法可以从余弦导出真正的距离度量,在同一篇维基百科文章中也提到过:https ://en.wikipedia.org/wiki/Cosine_similarity#Angular_distance_and_similarity

于 2013-12-11T09:11:15.570 回答