Sometimes, people may want a pass-by-reference in R, but unfortunately, R doesn't fully support this. However, there are various work arounds on this, and here is an example:
Let's say we want to make a function that change all NA values in a vector to 0. The most common way to do this in R is like this:
a <- c(1, NA, 2, NA, 3)
na2zero <- function(x){
x[is.na(x)] <- 0
return(x)
}
a <- na2zero(a); print(a)
However, a big problem of this approach is that an intermediate object with the same length of a is created and then be assigned to a. This may cause a problem when the size of a is very large. Moreover, in many cases where recursion is needed, this approach may not work. The question is how can we write a function which modifies an external object inside of the function.
Will global assignment ( <<- ) work? Unfortunately, no, at least not directly. Here is the example:
x <- c(1, NA, 2, NA, 3)
a <- c(1, NA, 2, NA, 3)
na2zero <- function(x){
x[is.na(x)] <<- 0
}
na2zero(a); cat("x=", x, "\n"); cat("a=", a, "\n")
We notice that we call the function on a, but instead of changing the NA values in a, the function takes the x literally and changes external object x. How can we make global assignment dynamic, instead of sticking to the name "x"? Here is how:
x <- c(1, NA, 2, NA, 3)
a <- c(1, NA, 2, NA, 3)
na2zero <- function(x){
tmp <- substitute(expression(x[is.na(x)] <<- 0))
eval(eval(tmp))
}
na2zero(a); cat("x=", x, "\n"); cat("a=", a, "\n")
na2zero(x); cat("x=", x, "\n"); cat("a=", a, "\n")
Why does it work this way? It is related to R's lexical scoping. More details can be found in R's manual, or do help.search("scoping") in R.
No comments:
Post a Comment