performance - 最有效的 R 余弦计算

标签 performance r linear-algebra

我有两个值向量和一个权重向量,我需要计算余弦相似度。由于复杂的原因,我一次只能计算一对的余弦。但我必须这样做数百万次。

cosine_calc <- function(a,b,wts) {
  #scale both vectors by the weights, then compute the cosine of the scaled vectors
  a = a*wts
  b = b*wts
  (a %*% b)/(sqrt(a%*%a)*sqrt(b%*%b))
}

有效,但我想尝试从中获得更好的性能。

示例数据:
a = c(-1.2092420, -0.7053822, 1.4364633, 1.3612304, -0.3029147, 1.0319704, 0.6707610, -2.2128987, -0.9839970, -0.4302205)
b = c(-0.69042619, 0.05811749, -0.17836802, 0.15699691, 0.78575477, 0.27925779, -0.08552864, -1.31031219, -1.92756861, -1.36350112)
w = c(0.26333839, 0.12803180, 0.62396023, 0.37393705, 0.13539926, 0.09199102, 0.37347546, 1.36790007, 0.64978409, 0.46256891)
> cosine_calc(a,b,w)[,1]
[1,] 0.8390671

question指出在 R 中有其他预定义的余弦函数可用,但没有说明它们的相对效率。

最佳答案

您使用的所有功能是.Primitive (因此已经直接调用编译代码),因此除了使用优化的 BLAS 重新构建 R 之外,很难找到一致的速度增益。话虽如此,对于较大的向量,这里有一个可能更快的选项:

cosine_calc2 <- function(a,b,wts) {
  a = a*wts
  b = b*wts
  crossprod(a,b)/sqrt(crossprod(a)*crossprod(b))
}

all.equal(cosine_calc1(a,b,w),cosine_calc2(a,b,w))
# [1] TRUE

# Check some timings
library(rbenchmark)
# cosine_calc2 is slower on my machine in this case
benchmark(
  cosine_calc1(a,b,w),
  cosine_calc2(a,b,w), replications=1e5, columns=1:4 )
#                    test replications user.self sys.self
# 1 cosine_calc1(a, b, w)       100000      1.06     0.02
# 2 cosine_calc2(a, b, w)       100000      1.21     0.00

# but cosine_calc2 is faster for larger vectors
set.seed(21)
a <- rnorm(1000)
b <- rnorm(1000)
w <- runif(1000)
benchmark(
  cosine_calc1(a,b,w),
  cosine_calc2(a,b,w), replications=1e5, columns=1:4 )
#                    test replications user.self sys.self
# 1 cosine_calc1(a, b, w)       100000      3.83        0
# 2 cosine_calc2(a, b, w)       100000      2.12        0

更新:

分析表明,将每个向量乘以权重向量花费了相当多的时间。
> Rprof(); for(i in 1:100000) cosine_calc2(a,b,w); Rprof(NULL); summaryRprof()
$by.self
             self.time self.pct total.time total.pct
*                 0.80    45.98       0.80     45.98
crossprod         0.56    32.18       0.56     32.18
cosine_calc2      0.32    18.39       1.74    100.00
sqrt              0.06     3.45       0.06      3.45

$by.total
             total.time total.pct self.time self.pct
cosine_calc2       1.74    100.00      0.32    18.39
*                  0.80     45.98      0.80    45.98
crossprod          0.56     32.18      0.56    32.18
sqrt               0.06      3.45      0.06     3.45

$sample.interval
[1] 0.02

$sampling.time
[1] 1.74

如果您可以在数百万次调用该函数之前进行加权,则可以为您节省相当多的时间。 cosine_calc3比使用小向量的原始函数略快。字节编译函数应该会给你另一个边际加速。
cosine_calc3 <- function(a,b) {
  crossprod(a,b)/sqrt(crossprod(a)*crossprod(b))
}
A = a*w
B = b*w
# Run again on the 1000-element vectors
benchmark(
  cosine_calc1(a,b,w),
  cosine_calc2(a,b,w),
  cosine_calc3(A,B), replications=1e5, columns=1:4 )
#                    test replications user.self sys.self
# 1 cosine_calc1(a, b, w)       100000      3.85     0.00
# 2 cosine_calc2(a, b, w)       100000      2.13     0.02
# 3    cosine_calc3(A, B)       100000      1.31     0.00

关于performance - 最有效的 R 余弦计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8158867/

相关文章:

R:获取排序向量中元素的索引

mysql - BETWEEN 查询的性能较差

r - 仅保留标签的文本

r - 画一个圆圈以突出显示 R 中曲线的最大值

Python 代码比相同的 C++ 代码慢得多?

performance - 在 DB2 中声明全局临时表与创建全局临时表

.net - Microsoft Research 的 Sho dll 与开源 Math.NET 数字项目相比如何

algorithm - 计算 2x2 矩阵幂的最快方法

r - 导出带有固定缩放和边界框的传单 map ,无需填充

matlab - 计算点集和引用点集之间的马氏距离