使用scikit learn KNeighborsClassifier的余弦距离

29

能否使用类似于1 - 余弦相似度的方法来使用scikit learn的KNeighborsClassifier?

这个回答说不行,但是在KNeighborsClassifier文档中,提到了DistanceMetrics中提到的度量标准是可用的。距离度量标准并不包括显式的余弦距离,可能是因为它实际上不是一种距离,但据说可以将一个函数输入度量标准中。我尝试将scikit learn线性内核输入到KNeighborsClassifier中,但是它给出一个错误,说这个函数需要两个数组作为参数。有其他人试过吗?


KNN分类器可能使用一些依赖于三角不等式的优化。余弦度量不遵守它,因此不能保证KNN的正确行为。 - Artem Sobolev
3
余弦度量可以通过满足三角不等式来实现,而且即使没有显式实现,也可以实现相同的排序。有关详细信息,请参见我的答案。 - Raff.Edward
我不清楚为什么现在无法明确地在文档中使用why。这些年发生了什么变化吗? - Andrea Ciufo
2个回答

71
余弦相似度通常定义为 xT y / (||x|| * ||y||),如果它们相同,则输出1,如果它们完全不同,则输出-1。该定义在技术上不是一个度量,因此您不能使用像球和kd树这样的加速结构。如果您强制scikit learn使用暴力方法,只要将自定义距离度量对象传递给它,就应该能够将其用作距离。如果您想使用球树,则有将余弦相似度转换为有效距离度量的方法(您可以在JSAT library中找到其中一种方法)。
请注意,xT y / (||x|| * ||y||) = (x/||x||)T (y/||y||)。欧几里得距离可以等价地写为sqrt(xTx + yTy − 2 xTy)。如果我们在将数据点提供给KNeighborsClassifier之前对其进行归一化,则对于所有的x,都有x^T x = 1。因此,欧几里得距离将退化为sqrt(2 − 2x^T y)。对于完全相同的输入,我们会得到sqrt(2-2*1) = 0,对于完全相反的输入,我们会得到sqrt(2-2*-1)= 2。它显然是一个简单的形状,因此您可以通过归一化数据,然后使用欧几里得距离来获得与余弦距离相同的排序。只要使用uniform权重选项,结果就与使用正确的余弦距离相同。

1
太简单了。感谢Raff提供这个优雅的解决方案 :) - Itachi
如果这些值既有正数又有负数,这个方法还能用吗?需要改变归一化的方式吗? - Eoin Ó Coinnigh
这对于任何值都适用,无论是正数还是负数。您只需要将每个向量除以它的2范数即可。 - Raff.Edward

1
KNN家族类的构造函数有一个名为metric的参数,您可以在最近邻模型中切换要使用的不同距离度量。 可在此处找到一系列可用的距离度量。
如果您想在排名和分类问题中使用余弦度量,可以在归一化特征向量上使用范数2欧几里得距离,这将给您相同的排名/分类(由argmax或argmin操作进行的预测)结果。

2
正如在问题中已经观察到的那样。该列表没有提及余弦距离。 - oulenz
@oulenz 他的意思是,使用L2(欧几里得)范数对数据进行归一化后,norm(data)与cosine(data)是相同的,因为欧几里得范数包含角度和大小,而余弦只包含角度(由于数据已经被归一化为单位向量长度,大小不是一个因素)。 - Maximus12793
@Maximus12793 是的,那部分是在我的评论之后编辑的。 - oulenz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接