匹配元素的执行时间不同

时间:2015-06-27 14:58:48

标签: r

我是R的初学者,正在探索可用于在向量中找到匹配元素(位置和布尔值)的不同选项。我有几个选项要做,我想看看每个的执行时间。令我惊讶的是,尽管他们做了同样的事情,但他们花了不同的时间。

有人可以对差异有所了解。

下面是查找匹配元素索引的脚本。尽管match只找到了第一个索引,但which花费的时间更短。

> obj<-c('a','b','c','d')
> 
> system.time( replicate(10000, match('c',obj) ) )
   user  system elapsed 
   0.04    0.00    0.05 
> system.time( replicate(10000, which('c'==obj) ) )
   user  system elapsed 
   0.04    0.00    0.03 

对于返回布尔值,时间也不同。

> system.time( replicate(10000, is.element('c',obj) ) )
   user  system elapsed 
   0.05    0.00    0.05 
> system.time( replicate(10000, 'c' %in% obj) )
   user  system elapsed 
   0.04    0.00    0.05 
> system.time( replicate(10000, any('c'==obj) ) )
   user  system elapsed 
   0.02    0.00    0.02 

非常感谢任何光明。

3 个答案:

答案 0 :(得分:8)

match需要构建一个哈希表,这是一项代价高昂的操作,只有在许多元素中搜索匹配时才有价值。 %in%match的包装器。

which(x == y)在向量上循环两次(一个用于测试相等性,一个用于返回TRUE的索引。any(x == y)的行为类似于which但停止循环一次找到TRUE

match仅返回第一个匹配,which返回所有匹配。

您可以比较搜索匹配项的元素数量的性能,例如:

n = seq_len(1e2)
tab = seq_len(1e5)

ans = lapply(n, function(n) {
                  x = seq_len(n)
                  summary(microbenchmark::microbenchmark(match = match(x, tab),
                                                         which = unlist(lapply(x, function(X) which(X == tab))),
                                                         'in' = x %in% tab, 
                                                         any = unlist(lapply(x, function(X)any(X == tab))),
                                                         unit = "ms",
                                                         times = 15))$median
                })

plot(NULL, xlim = c(1, length(ans)), ylim = range(unlist(ans)))
lines(sapply(ans, "[[", 1), col = "red")
lines(sapply(ans, "[[", 2), col = "blue")
lines(sapply(ans, "[[", 3), col = "pink")
lines(sapply(ans, "[[", 4), col = "lightblue")
legend("topleft", fill = c("red", "blue", "pink", "lightblue"), legend = c("match", "which", "in", "any"))

enter image description here

编辑 2016年5月4日:

在R&gt; = 3.3.0中,当x中的match(x, table)length(x) == 1L时,会进行简单的线性搜索,直到找到第一个匹配项并且{{{}}开销为match。 1}}的设置是避免的:

enter image description here

答案 1 :(得分:1)

我认为这些功能在效率上有所不同的原因并没有“明确”的答案。通常,提供相同输出的两个功能不需要同样有效。另一方面,可观察到的效率差异通常取决于输入(大小,格式)和使用函数的方式。

在您的示例中,is.element%in%实际上是相同的,因为他们只是简单地调用match来完成他们的工作。请参阅?is.element?match以获取说明,并is.element(R控制台中没有括号)了解该功能的用途。

第三个函数(any)是一个原始函数。这些函数通常非常有效,因为它们直接执行C例程。处理原始函数的方式与R中的“常规”函数不同。

答案 2 :(得分:1)

您可以使用microbenchmark并查看哪一个更有效:

library(microbenchmark)
microbenchmark(match('c',obj),which('c'==obj),is.element('c',obj) , 'c' %in% obj,any('c'==obj),times =10000)
Unit: nanoseconds
                 expr min   lq      mean median   uq     max neval cld
      match("c", obj) 489  978 1126.1920    979  980 1209606 10000  b 
    which("c" == obj) 489  978 1036.7159    979  980   31770 10000  b 
 is.element("c", obj) 978 1467 1810.8117   1468 1956 1150469 10000   c
         "c" %in% obj 978 1468 1826.2425   1469 1957   27860 10000   c
      any("c" == obj)   0    2  355.7135    490  491   23461 10000 a  

有100万次

microbenchmark(match('c',obj),which('c'==obj),is.element('c',obj) , 'c' %in% obj,any('c'==obj),times =1000000)
Unit: nanoseconds
                 expr min   lq      mean median   uq      max neval  cld
      match("c", obj) 489  978  995.9749    979  980  4391720 1e+06  b  
    which("c" == obj) 489  978 1013.2343    979  980  1193478 1e+06  b  
 is.element("c", obj) 978 1467 1663.1172   1468 1956  1202763 1e+06   c 
         "c" %in% obj 978 1468 1869.0499   1469 1957 56815228 1e+06    d
      any("c" == obj)   0    2  348.8258    490  491  1186147 1e+06 a