为什么余弦距离比在scikitlearn中与DBSCAN算法使用欧氏距离要慢得多

时间:2015-03-07 17:44:45

标签: python scikit-learn

我将从包scikit-learn为DBSCAN算法使用两个度量(欧几里德距离和余弦相似度)。

问题在于使用欧几里德距离比使用余弦相似度要快得多。

代码:

// using euclidean distance    
DBSCAN(eps=0.02, min_samples=5, metric="euclidean").fit(data)

// using cosine similarity
DBSCAN(eps=0.02, min_samples=5, metric=cosine_distance).fit(data)

有没有人知道这种速度与余弦相似性差异的原因?

2 个答案:

答案 0 :(得分:2)

我对scikit-learn一无所知,但我可以猜到为什么从数学角度来看它可能会变慢。


<强>解释

假设你有两个 n 维度的向量( A B )。

Euclidean distance of two vectors计算为

Sqrt((A_1 - B_1)^2 + (A_2 - B_2)^2 + ... + (A_N - B_N)^2)

其中A_m A 中的m th 元素。要计算它,您需要计算 n 差异, n 产品和 1 平方根。

Cosine of two vectors定义为

cos(x) = A.B / |A||B|

,其中

A.B = A_1 * B_1 + A_2 * B_2 + ...  A_n * B_n
|A| = Sqrt((A_1)^2 + (A_2)^2 + ... + (A_N)^2)

所以 n A.B和2. n 乘法的乘法得到|A||B|


<强>比较

Euclidean 距离需要 n 减法和 n 乘法; 余弦相似度需要3. n 乘法。

假设减法是计算密集型的(它几乎肯定不那么强烈),那么对于欧几里得而言,它是 n 。余弦的 n

换句话说,它的至少慢50%来获得余弦差异而不是欧几里德距离。我不知道scikit-learn如何使用这些指标,或 n 的大小,但这可能是您看到差异的原因。

答案 1 :(得分:0)

假设cosine_distance是Python函数:

虽然sklearn允许您指定自定义距离函数,但其​​性能并不是特别好。对于每个距离,它需要设置回调到Python 解释器。这自然比内置函数使用的编译本机代码慢得多。

这种开销似乎很快就用Python解决了。可能有必要修改sklearn源(添加新的内置函数)或使用具有良好JIT的Java之类的东西(例如,ELKI可以通过这种方式扩展,并且对于自定义距离更快)。

Jython听起来很酷(JVM上的Python),但据我所知,不支持numpy,因此也不支持sklearn。而且我不知道它是否可以将Python编译成字节码,或者它是否只是一个解释器。