Question

I found out that zoo's transform is not able to use additional (i.e. not part of the zoo object) variables when used in a function body.

Let me explain:

I entered the following code at the prompt to create a small two-column zoo object z and to add a new column calculated from an existing column and a variable x:

library(zoo)
z <- zoo(matrix(1:10, ncol=2, dimnames=list(NULL, c("a", "b"))), order.by=2001:2005)
x <- 2
transform(z, c = x*a)

I got the desired result, a zoo object with a new colum c. No problem here.

Now I'd like to use transform in a function body; the variable for the calculation is passed as a parameter to the function:

rm(x)
f <- function(data, x) { transform(data, c = x*a) }
f(z, 2)

This stops with Error in eval(expr, envir, enclos) (from #1) : object 'x' not found. If I assign x <- 2 at the prompt, it works (therefore the rm(x) above).

With dataframes (i.e. transform.data.frame) there is no problem.

I think that when transform.zoo calls transform.data.frame, the bindings of the formals of f are lost. I don't understand R's environments well enough to find out what exactly is wrong here.

Edited to add: Not only can transform not get the formals but also no variables from inside the function body.

Is there a way to make transform see x? (I know I could work without transform, but it's a nice tool for short, succinct code.)

Was it helpful?

Solution

I think the best advice is: Don't do that!

transform(), with(), subset() are really sugar for use at the top level, to make things somewhat easier to write data manipulation code. If you are writing functions you should use the general replacement functions [<- and [[<- depending on what you are doing.

If you don't believe me, see the Warning in ?transform

Warning:

    This is a convenience function intended for use interactively.
    For programming it is better to use the standard subsetting
    arithmetic functions, and in particular the non-standard
    evaluation of argument ‘transform’ can have unanticipated
    consequences.

What I mean by using [<- or [ or other functions is to write f like this

f <- function(obj, x) {
  cd <- coredata(obj)
  cd <- cbind(cd, c = x * cd[, "a"])
  zoo(cd, index(obj), attr(obj, "frequency"))
}

f(z, 2)

Which gives the desired result

> transform(z, c = x*a)
     a  b  c
2001 1  6  2
2002 2  7  4
2003 3  8  6
2004 4  9  8
2005 5 10 10
> f(z, 2)
     a  b  c
2001 1  6  2
2002 2  7  4
2003 3  8  6
2004 4  9  8
2005 5 10 10

f is complicated because coredata(obj) is a matrix. It might be neater to

f2 <- function(obj, x) {
    cd <- as.data.frame(coredata(obj))
    cd[, "c"] <- x * cd[, "a"] ## or cd$c <- x * cd$a
    zoo(cd, index(obj), attr(obj, "frequency"))
}

f2(z, 2)

> f2(z, 2)
     a  b  c
2001 1  6  2
2002 2  7  4
2003 3  8  6
2004 4  9  8
2005 5 10 10

You really need to understand environments and evaluation frames to use transform() - well you can't you'd need to learn to use eval(), which is what transform() calls internally, and specify the correct values for envir (the environment in which to evaluate), and enclos the enclosure. See ?eval.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top