遇到类似问题,我正在寻找比此问题提供的更通用的解决方案:How do I substitute symbols in a language object?
我有一个未评估的表达式foo <- quote(bar + baz)
,它是其他表达式中的变量:qux <- quote(bla + foo)
。
我们可以查看:
exists("foo", envir=.GlobalEnv) & class(foo)=="call"
[1] TRUE
exists("qux", envir=.GlobalEnv) & class(qux)=="call"
[1] TRUE
现在我想编写一个广义函数,将(解析?)qux
分解为组件表达式,替换 .GlobalEnv
中存在的函数和属于call
类及其值:
replaceFUN <- function(x) {
# do something
}
运行replaceFUN(qux)
应返回:
bla + (bar + baz)
实际问题的背景:
我正在建立一个量化交易规则回测试引擎。我的目标是延迟对quote()d表达式的评估,例如在定义之后的规则和指标计算。
require(data.table)
require(TTR) # for the `SMA` function
DT <- data.table(Instrument=rep("SPX",3),Date=1:3, Close=c(1050, 1052, 1051))
# define parameters
nSMA <-2
t <- 2
# define indicators
time.filter <- quote( Date==t )
moving.average <- quote( SMA(Close, nSMA) )
buy <- quote( Close > moving.average & time.filter )
AddColumn <- function(x, colname) {
DT[,eval(substitute(colname)):=eval(x, envir=.SD)]
}
AddColumn(time.filter, "filter")
Instrument Date Close filter
1: SPX 1 1050 FALSE
2: SPX 2 1052 TRUE
3: SPX 3 1051 FALSE
AddColumn(moving.average, "MA")
Instrument Date Close filter MA
1: SPX 1 1050 FALSE NA
2: SPX 2 1052 TRUE 1051.0
3: SPX 3 1051 FALSE 1051.5
AddColumn(buy, "Buy")
Error in Close > moving.average & time.filter :
operations are possible only for numeric, logical or complex types
这显然会引发错误,因为AddColumn
函数缺少解析嵌套moving.average
和time.filter
变量的机制(以及用户定义和嵌套的任何其他变量)。 buy
中的规则嵌套是为了提高可读性而确实是一种语法糖。
答案 0 :(得分:4)
我刚才解决了一个非常类似的问题。查看[.data.table
的{{3}}并查看其中的deconstruct_and_eval
和construct
功能。它应该给你足够的信息继续。
答案 1 :(得分:3)
从[.data.table
source code自定义此功能
产生了所需的通用解决方案:
deconstruct_and_eval = function(expr, envir = parent.frame(), enclos = parent.frame()) {
if (!mode(expr) %in% c("call", "expression"))
return(expr)
if (length(expr) == 1) {
if (is.call(expr[[1]])) return (deconstruct_and_eval(expr[[1]]))
else return(expr)
}
if (expr[[1]] == quote(eval) && length(expr) < 3) {
return(deconstruct_and_eval(eval(expr[[2]], envir, enclos), envir, enclos))
}
lapply(expr, function(m) {
if (is.call(m)) {
if (m[[1]] == quote(eval)) eval(m[[2]], envir, enclos)
else deconstruct_and_eval(m, envir, enclos)
} else {
# begin edit
if(exists(as.character(m),envir=.GlobalEnv)) {
if(!is.function(eval(m)))
eval(m)
else
m
} else
# end edit
m
}
})
}
使用原始问题变量运行函数会产生:
deconstruct_and_eval(qux)
[[1]]
`+`
[[2]]
bla
[[3]]
bar + baz
然后可以使用source code中的construct
函数重建此解构列表:
construct(deconstruct_and_eval(qux))
bla + (bar + baz)
应用于实际问题:
deconstruct_and_eval(buy)
[[1]]
`&`
[[2]]
[[2]][[1]]
`>`
[[2]][[2]]
Close
[[2]][[3]]
SMA(Close, nSMA)
[[3]]
Date == t
construct(deconstruct_and_eval(buy))
Close > SMA(Close, nSMA) & Date == t