假设我想在R
中写一个函数,它是一些数据的一对充分统计量的函数。例如,假设函数foo.func
只依赖于数据样本的样本均值。为了方便,我认为用户可能喜欢将随机变量的样本传递给foo.func
(在这种情况下,foo.func
计算样本均值),或样本均值本身,这就是foo.func
所需要的。出于效率的考虑,如果调用foo.func
等多个可以取样本均值的函数,则首选后者。在这种情况下,平均值只需要计算一次(在我遇到的实际问题中,所讨论的样本统计可能是计算密集型的)。
总之,我想把foo.func
写得对初学者(传入数据,让函数计算充分统计)和专家(为了效率预先计算充分统计并传入)都可以访问。推荐的做法是什么?我有一个逻辑标志传入吗?多个参数?有些方法可以这样做:
#optional arguments
foo.func <- function(xdata, suff.stats=NULL) {
if (is.null(suff.stats)) {
suff.stats <- compute.suff.stats(x)
}
#now operate on suff.stats
}
或
#flag input
foo.func <- function(data.or.stat, gave.data=TRUE) {
if (gave.data) {
data.or.stat <- compute.suff.stats(data.or.stat)
}
#now operate on data.or.stat
}
我倾向于前者,我认为
R实现多态性的方式是通过CLOS (Common Lisp的OO)模型,其中方法与泛型函数(动词)而不是类(名词)相关联。例如,
# suprising that there is not an equivalent function in R
# to propagate inheritance...
addclass <- function(x,classname) structure(x,class=append(class(x),classname))
# this should be your main function that does stuff
# here, the identity function is assigned for example
dostuff <- identity
# define generic function and methods
foo <- function(x,...) UseMethod("foo")
foo.raw <- function(x,...) dostuff(mean(x))
foo.stats <- function(x,...) dostuff(x)
# define two types of inputs
x <- 1:10
x <- addclass(x,"raw")
y <- 5
y <- addclass(y,"stats")
# apply
foo(x)
# [1] 5.5
foo(y)
# [1] 5
# attr(,"class")
# [1] "numeric" "stats"
这个例子使用了R的S3
OOP模型,我认为这已经足够了;S4
更现代和安全,但增加了很多样板文件。
还可以在参数中嵌入函数,如:
foo.func <- function(x, suff.stats = foo.func.suff.stat(x)){
# your code here
}
例如:
foo.func <- function(x, avg = mean(x)){
return(avg)
}
foo.func(1:20)
foo.func(avg = 42)
或者,您可以对各种参数使用NULL
的默认设置,并测试is.null(argument)
,或者简单地检查missing(argument)
的值对于您可能计算的每个参数。
更新1:我错误地建议使用默认值NA
:使用NULL
要合适得多。使用NA
和is.na()
对于矢量输入会表现得很奇怪,而NULL
只是一个单独的对象——不能创建NULL值的矢量,所以is.null(argument)
的行为和预期的一样。对不起,我忘了。