我经常在R中编写函数,理论上,参数应该缺省为Inf或-Inf。但是,将参数默认为NULL并检查是否为该参数提供了值也是有意义的。例如,考虑以下两个函数
myfunc <- function(numVec, cap=NULL){
if(!is.null(cap)) numVec <- pmin(numVec, cap)
return(sum(numVec) + mean(numVec))
}
myfunc <- function(numVec, cap=Inf){
numVec <- pmin(numVec, cap)
return(sum(numVec) + mean(numVec))
}对于相同的输入,它们将始终返回相同的结果。但是哪一种设计更好呢?第一种方法可能比第二种方法的效率稍高一些,但第二种方法更优雅。显然,这是一个非常简单的例子,但是当面对这个设计决策时,有没有人有一些好的经验法则呢?
发布于 2014-09-18 00:10:08
我不确定这是否构成了一个答案,但这篇评论太长了,也许会有所帮助。
内存中的大小
require(pryr)
object_size(Inf)
# 48 B
object_size(NULL)
# 0 B基准测试
require(microbenchmark)
numVec2 <- numVec1 <- 1:3
cap1.1 <- Inf
cap2.1 <- NULL
cap2.2 <- cap1.2 <- 2
ex1.1 <- expression({ numVec1 <- pmin(numVec1, cap1.1); numVec1 })
ex1.2 <- expression({ numVec1 <- pmin(numVec1, cap1.2); numVec1 })
ex2.1 <- expression({ if(!is.null(cap2)) numVec2 <- pmin(numVec2, cap2.1); numVec2 })
ex2.2 <- expression({ if(!is.null(cap2)) numVec2 <- pmin(numVec2, cap2.2); numVec2 })
microbenchmark(ex1.1, ex1.2, ex2.1, ex2.2, times = 1000)
# Unit: nanoseconds
# expr min lq median uq max neval
# ex1.1 42 46.5 50 116.5 33841 1000
# ex1.2 40 46.0 49 117.5 23931 1000
# ex2.1 42 48.0 52 116.0 28167 1000
# ex2.2 47 53.0 55 122.0 3014 1000分析
require(lineprof)
lp1.1 <- lineprof(eval(ex1.1), torture = TRUE)
lp1.2 <- lineprof(eval(ex1.2), torture = TRUE)
lp2.1 <- lineprof(eval(ex2.1), torture = TRUE)
lp2.2 <- lineprof(eval(ex2.2), torture = TRUE)
lp1.1
# Reducing depth to 2 (from 5)
# time alloc release dups ref src
# 1 0.001 0.001 0.000 0 character(0)
# 2 0.007 0.001 0.005 0 "eval" eval
# 3 0.011 0.003 0.003 5 c("eval", "eval") eval/eval
lp1.2
# Reducing depth to 2 (from 5)
# time alloc release dups ref src
# 1 0.001 0.001 0.000 0 character(0)
# 2 0.012 0.004 0.001 5 c("eval", "eval") eval/eval
lp2.1
# time alloc release dups ref src
# 1 0.002 0 0 0 character(0)
lp2.2
# time alloc release dups ref src
# 1 0.001 0 0 0 c("eval", "eval") eval/eval
# 2 0.001 0 0 0 character(0)因此,检查!is.null(caps)似乎(毫不奇怪)总体上比让pmin处理Inf要高效得多。因此,在超高效代码和数学优雅之间存在权衡。
然而,事实证明,检查cap != Inf比检查!is.null(cap)更快
microbenchmark(!is.null(cap2.1), cap1.1 != Inf, times = 1000)
# Unit: nanoseconds
# expr min lq median uq max neval
# !is.null(cap2.1) 130 145 152 203 4660 1000
# cap1.1 != Inf 87 100 107 155 1317 1000所以事实证明,在这种情况下,你可以既吃蛋糕又吃蛋糕:
myfunc <- function (numVec, cap = Inf) {
if(cap != Inf) numVec <- pmin(numVec, cap)
sum(numVec) + mean(numVec)
}https://stackoverflow.com/questions/25894643
复制相似问题