2017-02-21 91 views
1

我目前正在处理一个问题。我正在为一些特定发行版打包,其中我希望创建一个适合某些数据的函数。为此,我想使用例如fitdistr函数。问题是我不知道混合物将由哪些分布和重量以及组分的数量组成。因此我需要一个函数来动态创建一些指定混合的密度函数,以便函数可以使用它。例如,如果用户将拨打:动态创建函数和表达式

fitmix(data,dist=c(norm,chisq),params=list(c(mean=0,sd=3),df=2),wights=c(0.5,0.5)) 

使用ML方法中的代码需要创建一个密度函数

function(x,mean,sd,df) 0.5*dnorm(x,mean,sd)+0.5*dchisq(x,df) 

所以它可以调用optimfitdistr

一个明显的解决方案是使用大量的paste + eval + parse但我不认为这是最优雅的解决方案。一个很好的解决方案可能隐藏在非标准评估和表达式操纵的某个地方,但我在这个问题上没有足够的技巧。

P.S.参数可以用作优化器的起始值。

+0

你有没有尝试什么吗?这基本上就像是一个“请为我编码”这个问题,在本网站不鼓励。如果您可以提出更具体的问题或至少显示您尝试过的代码,那可以改善您的问题。 – MrFlick

+0

这个例子是真实任务的简化版本,所以我的代码对这个问题没有帮助。我可以使用lapply(seq_along(D),function(i)paste(dist [i],paste(“(x,”,paste(names(params [[i]))粘贴来创建调用,崩溃=“,”),“)”,sep =“”),sep =“”))+将它们粘贴在一起,并尝试as.call,但没有任何好的结果 –

回答

2

建筑表达式在R中是相对直接的,其功能类似于as.callbquote以及函数是R中第一类对象的事实。使用动态特征构建函数有点棘手。这里有一些可能帮助的功能

to_params <- function(l) { 
    z <- as.list(l) 
     setNames(lapply(names(z), function(x) bquote(args[[.(x)]])), names(z)) 
} 

add_exprs <- function(...) { 
     x <- list(...) 
    Reduce(function(a,b) bquote(.(a) + .(b)), x) 
} 

get_densities <- function(f) { 
    lapply(paste0("d", f), as.name) 
} 

weight_expr <- function(w, e) { 
    bquote(.(w) * .(e)) 
} 
add_params <- function(x, p) { 
    as.call(c(as.list(x), p)) 
} 
call_with_x <- function(fn) { 
    as.call(list(fn, quote(x))) 
} 

fitmix <- function(data, dist, params, weights) { 
    fb <- Reduce(add_exprs, Map(function(d, p, w) { 
     weight_expr(w, add_params(call_with_x(d), to_params(p))) 
    }, get_densities(dist), params, weights)) 
    f <- function(x, args) {} 
    body(f) <- fb 
    f 
} 

请注意,我更改了一些参数的类型。分布应该是字符串。参数应该是一个命名向量的列表。它将与受理工作,这样

ff <- fitmix(data, dist=c("norm","chisq"), params=list(c(mean=0,sd=3),c(df=2)), 
    weights=c(0.5,0.5)) 

它返回一个函数,它的x和命名参数列表。你可以把它像

ff(0, list(mean=3, sd=2, df=2)) 
# [1] 0.2823794 

返回相同的值

x <- 0 
0.5 * dnorm(x, mean = 3, sd = 2) + 0.5 * dchisq(x, df = 2) 
# [1] 0.2823794