Substitua, avaliar, Bquote, Do.Call… Algumas orientações para substituir expressões
-
22-09-2019 - |
Pergunta
Eu gostaria de programar uma aula de séries temporais. A idéia é que eu instancie um objeto com uma expressão e outros objetos de série temporal, por exemplo
(duas séries temporais)
x <- ts(rnorm(10), frequency = 4, start = c(1959, 2))
y <- ts(rnorm(10), frequency = 4, start = c(1959, 2))
(uma série temporal, definida para ser a soma de x e y)
z <- exprTs("x+y", parents=list(x=x, y=y))
(Faça parte da série)
window(z, start=1960, end=1960.75)
O problema é: como posso avaliar a expressão? Eu tentei o seguinte:
#(constructor for class)
exprTs <- function(expr, parents) {
res = list(expr=expr, parents=parents)
class(res) <- "exprTs"
res
}
#(window method)
window.exprTs <- function(z, ...) {
eval(substitute(z$expr, lapply(z$parents, window, ...)))
#do.call(z$expr, lapply(z$parents, window, ...))
}
Não consigo fazer o método da janela funcionar.
Se você pudesse me orientar sobre como usar o substituto, avaliar, fazer.Call apropriadamente, isso seria muito útil.
Solução
Um problema é que você está especificando a expressão como uma string para que ela seja avaliada em uma string. Se você deseja analisar uma string em uma expressão, você precisa usar o parse
comando:
> "x+y"
[1] "x+y"
> parse(text="x+y")
expression(x+y)
attr(,"srcfile")
<text>
Mas sim, por que não usar apply
e funções em vez disso?
Outras dicas
Você pode estar pensando sobre isso da maneira errada e apenas complicações complacentes. Já existe uma adição definida para ts
objetos:
R> set.seed(42)
R> x <- ts(rnorm(10), frequency = 4, start = c(1959, 2))
R> y <- ts(rnorm(10), frequency = 4, start = c(1959, 2))
R> z <- x + y
R> cbind(x,y,z)
x y z
1959 Q2 1.37096 1.3049 2.6758
1959 Q3 -0.56470 2.2866 1.7219
1959 Q4 0.36313 -1.3889 -1.0257
1960 Q1 0.63286 -0.2788 0.3541
1960 Q2 0.40427 -0.1333 0.2709
1960 Q3 -0.10612 0.6360 0.5298
1960 Q4 1.51152 -0.2843 1.2273
1961 Q1 -0.09466 -2.6565 -2.7511
1961 Q2 2.01842 -2.4405 -0.4220
1961 Q3 -0.06271 1.3201 1.2574
R>
Você realmente não precisa de um analisador de expressão para operar em objetos R.
Agora eu encontrei uma solução:
window.exprTs <- function(z, ...) {
names(z$parents)<-NULL
do.call(z$expr, lapply(z$parents, window, ...))
}
plus <- function(x, ...) if (nargs() == 1) x else x + Recall(...)
z <- exprTs(plus, parents=list(x=x, y=y))
Agora
window(z, start=1960, end=1960.75)
dá o resultado desejado.