3

同様の問題があるため、この質問に提供されているものよりも一般化された解決策を探しています:言語オブジェクトのシンボルを置き換えるにはどうすればよいですか?

評価されていない式があります。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.averagetime.filterbuy

4

2 に答える 2

4

少し前にこれと非常によく似た問題を解決していました。のソース コードを調べて、そこにある関数と関数[.data.tableを調べてください。続行するのに十分な情報が得られるはずです。deconstruct_and_evalconstruct

于 2013-10-12T00:10:51.963 に答える
3

[.data.tableソース コードからこの関数をカスタマイズ すると、目的の一般的なソリューションが得られます。

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

この分解されたリストは、ソース コード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
于 2013-10-13T16:06:07.300 に答える