使用带if选项的R函数时优化运行时
我的目标是优化我的R函数的运行时过程。 更具体地说,我的R函数包含各种if选项,例如,在运行使用该函数的模拟时,我需要修复函数选项。 是否有可能使R在不总是检查每个if选项的情况下使用该函数,即跳过所有其他选项并直接跳到预先指定的选项? 下面是一个具有两个函数的示例:使用带if选项的R函数时优化运行时,r,function,R,Function,我的目标是优化我的R函数的运行时过程。 更具体地说,我的R函数包含各种if选项,例如,在运行使用该函数的模拟时,我需要修复函数选项。 是否有可能使R在不总是检查每个if选项的情况下使用该函数,即跳过所有其他选项并直接跳到预先指定的选项? 下面是一个具有两个函数的示例:fun1()不带任何if/else选项和fun2()带选项。使用两个函数的两个循环,实现相同的计算,然后计算运行时 # Data x = rexp(100) fun1 = function(x){ v= sqrt(x)
fun1()
不带任何if/else选项和fun2()
带选项。使用两个函数的两个循环,实现相同的计算,然后计算运行时
# Data
x = rexp(100)
fun1 = function(x){
v= sqrt(x)
return(v)
}
fun2 = function(x, type = c("a", "b", "c","d","e","f")){
if(type == "a"){ v = mean(x) }
if(type == "b"){ v= median(x)}
if(type == "c"){ v= var(x)}
if(type == "d"){ v= sd(x)}
if(type == "e"){ v= sqrt(x)} # type == "e" does the same as fun1
if(type == "f"){ v= sum(x)}
return(v)
}
# No. of iterations for loops below
iter = 10000000
system.time(
for(i in 1:iter){
res = fun1(x)
}
)
# user system elapsed
# 19.42 0.06 19.72
system.time(
for(i in 1:iter){
res = fun2(x, type = "e")
}
)
# user system elapsed
# 33.10 0.05 33.56
在这里,第一个(无用的)循环比第二个循环快得多,因为函数不需要总是检查内部选项。
所以我的问题是,是否有可能使用
fun2()
,同时达到与使用fun1()
获得的运行时间相同的运行时间。tryCatch()
在这种情况下有帮助吗?通过对100个数字进行10万次的计算,您的基准测试似乎主要是测量“从R到低级代码的转换速度”的速度,而不是基本的计算时间,因此它可能测量的是错误的
在许多情况下,R的最佳性能来自将问题转换为矢量化形式,例如使用嵌套的ifelse(或我的首选项,dplyr::case\u when
)。(以下是我最喜欢的解释。)
在您的示例中,fun1
的转换速度更快(毫不奇怪),但如果在较长的数据集上运行矢量化计算,则性能很快就会变得非常类似于fun2
,对于n=100k或更大的数据集,性能基本相同。您可以看到,这两个函数对于小批量都是低效的,因为大部分时间都花在转换和计算上
有关更多建议,请查看以下内容:
库(tidyverse)
图书馆(微基准)
运行范围``fun3=函数(x,type=c(“a”,“b”,“c”,“d”,“e”,“f”){if(type==“e”){v=sqrt(x)}如何``type==“e”与fun1做的一样{if(type==“a”){v=mean(x)}if(type==“b”){v=median(x)}if(type==“c”){v=var(x)}if(type==“d”){v=sd(x)}if(type==“f)返回值}v}“我认为这几乎和乐趣1一样快,几乎和乐趣2一样有用。谢谢你的想法!那肯定会很有趣。但是,只有在使用type==“e”时,它才适合。因此,没有保持功能的灵活性,这是我的一个缺点。。
library(tidyverse)
library(microbenchmark)
run_ranges <- function(n) {
x = rexp(n)
summary(microbenchmark(fun1(x), fun2(x, "e"), unit = "ns", times = 1000))
}
ranges <- 10 ^ c(1:6)
sum_table <- tibble(ranges = rep(ranges, each = 2)) %>%
bind_cols(results = map_dfr(ranges, run_ranges))
ggplot(sum_table, aes(x = ranges, y = mean/ranges, color = expr)) +
geom_line() +
scale_x_log10(name = "#s per run", labels = scales::comma) +
scale_y_continuous(name = "ns per calculation", labels = scales::comma)