我的目标是在R中编写一个接受fractional polynomial(FP)系数的函数,并返回一个矢量化函数,该函数评估给定输入数字的指定FP。 FP定义有两个重要规则:
我目前的解决方案将FP函数构建为字符串,解析字符串并返回一个计算表达式的函数。我的问题是,是否有更好/更快的方式可以避免eval(parse())
- 可能使用某些substitute()
魔法。
函数必须处理,其中每个电源的系数数量事先未知,但在被调用时指定。最终的FP评估需要快,因为它经常被调用。
会很好不限于标准功率-2,-1,-0.5,0,0.5,1,2,3。理想情况,期望的函数将同时执行两个步骤:接受FP系数以及数字向量,并在仍然快速的情况下返回输入的FP值。
getFP <- function(p_2, p_1, p_0.5, p0, p0.5, p1, p2, p3, ...) {
p <- as.list(match.call(expand.dots=TRUE)[-1]) # all args
names(p) <- sub("^p", "", names(p)) # strip "p" from arg names
names(p) <- sub("_", "-", names(p)) # replace _ by - in arg names
## for one power and the i-th coefficient: build string
getCoefStr <- function(i, pow, coefs) {
powBT <- ifelse(as.numeric(pow), paste0("x^(", pow, ")"), "log(x)")
logFac <- ifelse(i-1, paste0("*log(x)^", i-1), "")
paste0("(", coefs[i], ")*", powBT, logFac)
}
onePwrStr <- function(pow, p) { # for one power: build string for all coefs
coefs <- eval(p[[pow]])
pwrStr <- sapply(seq(along=coefs), getCoefStr, pow, coefs)
paste(pwrStr, collapse=" + ")
}
allPwrs <- sapply(names(p), onePwrStr, p) # for each power: build string
fpExpr <- parse(text=paste(allPwrs, collapse=" + "))
function(x) { eval(fpExpr) }
}
一个例子是-1.5*x^(-1) - 14*log(x) - 13*x^(0.5) + 6*x^0.5*log(x) + 1*x^3
,它指定了系数(-1.5,-14,-13,6,1)的幂(-1,0,0.5,0.5,3)。
> fp <- getFP(p_1=-1.5, p0=-14, p0.5=c(-13, 6), p3=1)
> fp(1:3)
[1] -13.50000000 -14.95728798 0.01988127
答案 0 :(得分:6)
首先,我们创建一个将在序列中生成单个术语的函数
one <- function(p, c = 1, repeated = 1) {
if (p == 0) {
lhs <- substitute(c * log(x), list(c = c))
} else {
lhs <- substitute(c * x ^ p, list(c = c, p = p))
}
if (repeated == 1) return(lhs)
substitute(lhs * log(x) ^ pow, list(lhs = lhs, pow = repeated - 1))
}
one(0)
# 1 * log(x)
one(2)
# 1 * x^2
one(2, 2)
# 2 * x^2
one(2, r = 2)
# 1 * x ^ 2 * log(x)^1
one(2, r = 3)
# 1 * x ^ 2 * log(x)^2
此处的关键工具是substitute()
,其解释为here。
接下来我们编写一个将两个术语加在一起的函数。这再次使用替代:
add_expr_1 <- function(x, y) {
substitute(x + y, list(x = x, y = y))
}
add_expr_1(one(0, 1), one(2, 1))
我们可以使用它来创建一个函数来添加任意数量的术语:
add_expr <- function(x) Reduce(add_expr_1, x)
add_expr(list(one(0, 1), one(1, 1), one(2, 3)))
有了这些部分,最后的功能很简单 - 我们计算出代表的数量,然后使用Map()
为one()
,{{{{{}}的每个组合调用一次powers
1}}和coefs
:
reps