I have a function that needs to access a variable in its parent environment (scope from which the function is called). The variable is large in terms of memory so I would prefer not to pass it to by value to the function being called. Is there a standard way of doing this other than declaring the variable in the global scope? For example:
g <- function (a, b) { #do stuff}
f <- function(x) {
y <- 3 #but in my program y is very large
g(x, y)
}
I would like to access y in g(). So something like this:
g <- function (a) { a+y }
f <- function(x) {
y <- 3 #but in my program y is very large
g(x)
}
Is this possible?
Thanks
There is no advantage to "declaring the variable in the global scope" and it may not even be possible in R depending on what you mean by that. You certainly could use the second form. The action that causes duplicate or even triplicate copies of an object is assignment. You will need to describe in more detail what you are trying to illustrate by the code: y <- 3. That would not normally be needed inside a function that merely accessed an object named "y" that was located in an enclosing frame.
Storing variables in a declared environment will sometimes improve efficiency of access, but my understanding is that the efficiency is in terms of improved speed because a hash table is used. One accesses items in an environment in the same manner as one accesses list elements:
> evn <- new.env()
> evn$a <- rnorm(100000)
> ls(evn)
[1] "a"
> length(evn$a)
[1] 100000
The BigMemory project may offer facilities for this:
http://www.bigmemory.org/ .
It and Lumley's biglm may help with the large dataset mentioned in the comments.
Related
I want to add an environment to a search path and modify the values of variables within that environment, in a limited chunk of code, without having to specify the name of the environment every time I refer to a variable: for example, given the environment
ee <- list2env(list(x=1,y=2))
Now I would like to do stuff like
ee$x <- ee$x+1
ee$y <- ee$y*2
ee$z <- 6
but without appending ee$ to everything (or using assign("x", ee$x+1, ee) ... etc.): something like
in_environment(ee, {
x <- x+1
y <- y+2
z <- 6
})
Most of the solutions I can think of are explicitly designed not to modify the environment, e.g.
?attach: "The database is not actually attached. Rather, a new environment
is created on the search path ..."
within(): takes lists or data frames (not environments) "... and makes the corresponding modifications to a copy of ‘data’"
There are two problems with <<-: (1) using it will cause NOTEs in CRAN checks (I think? can't find direct evidence of this, but e.g. see here — maybe this only happens because of the appearance of assigning to a locally undefined symbol? I guess I could put this in a package and test it with --as-cran to confirm ...); (2) it will try to assign in the parent environment, which in a package context [which this is] will be locked ...
I suppose I could use a closure as described in section 10.7 of the Introduction to R by doing
clfun <- function() {
x <- 1
y <- 2
function(...) {
x <<- x + 1
y <<- y * 2
}
}
myfun <- clfun()
This seems convoluted (but I guess not too bad?) but:
will still incur problem #1 (CRAN check?).
I think (??) it won't work with variables that don't already exist in the environment (would need an explicit assign() for that ...)
doesn't allow a choice of which environment to operate in - it's necessarily going to work in the enclosing environment, not with arbitrary environment ee
Am I missing something obvious and idiomatic?
Thanks to #Nuclear03020704 ! I think with() was what I wanted all along; I was incorrectly assuming that it would also create a local copy of the environment, but it only does this if the data argument is not already an environment.
ee <- list2env(list(x=1,y=2))
with(ee, {
x <- x+1
y <- y+2
z <- 6
})
does exactly that I want.
Just had another idea, which also seems to have some drawbacks: using a big eval clause. Rather than make my question a long laundry list of unsatisfactory solutions, I'll add it here.
myfun <- function() {
eval(quote( {
x <- x+1
y <- y*2
z <- 3
}), envir=ee)
}
This does seem to work, but also seems very weird/mysterious! I hate to think about explaining it to someone who's being using R for less than 10 years ... I suppose I could write an in_environment() based on this, but I'd have to be very careful to capture the expression properly without evaluating it ...
What about with()? From here,
with(data, expr)
data is the data to use for constructing an environment. For the default with method this may be an environment, a list, a data frame, or an integer.
expr is the expression to evaluate.
with is a generic function that evaluates expr in a local environment constructed from data. The environment has the caller's environment as its parent. This is useful for simplifying calls to modeling functions. (Note: if data is already an environment then this is used with its existing parent.)
Note that assignments within expr take place in the constructed environment and not in the user's workspace.
with() returns value of the evaluated expr.
ee <- list2env(list(x=1,y=2))
with(ee, {
x <- x+1
y <- y+2
z <- 6
})
I just finished reading about scoping in the R intro, and am very curious about the <<- assignment.
The manual showed one (very interesting) example for <<-, which I feel I understood. What I am still missing is the context of when this can be useful.
So what I would love to read from you are examples (or links to examples) on when the use of <<- can be interesting/useful. What might be the dangers of using it (it looks easy to loose track of), and any tips you might feel like sharing.
<<- is most useful in conjunction with closures to maintain state. Here's a section from a recent paper of mine:
A closure is a function written by another function. Closures are
so-called because they enclose the environment of the parent
function, and can access all variables and parameters in that
function. This is useful because it allows us to have two levels of
parameters. One level of parameters (the parent) controls how the
function works. The other level (the child) does the work. The
following example shows how can use this idea to generate a family of
power functions. The parent function (power) creates child functions
(square and cube) that actually do the hard work.
power <- function(exponent) {
function(x) x ^ exponent
}
square <- power(2)
square(2) # -> [1] 4
square(4) # -> [1] 16
cube <- power(3)
cube(2) # -> [1] 8
cube(4) # -> [1] 64
The ability to manage variables at two levels also makes it possible to maintain the state across function invocations by allowing a function to modify variables in the environment of its parent. The key to managing variables at different levels is the double arrow assignment operator <<-. Unlike the usual single arrow assignment (<-) that always works on the current level, the double arrow operator can modify variables in parent levels.
This makes it possible to maintain a counter that records how many times a function has been called, as the following example shows. Each time new_counter is run, it creates an environment, initialises the counter i in this environment, and then creates a new function.
new_counter <- function() {
i <- 0
function() {
# do something useful, then ...
i <<- i + 1
i
}
}
The new function is a closure, and its environment is the enclosing environment. When the closures counter_one and counter_two are run, each one modifies the counter in its enclosing environment and then returns the current count.
counter_one <- new_counter()
counter_two <- new_counter()
counter_one() # -> [1] 1
counter_one() # -> [1] 2
counter_two() # -> [1] 1
It helps to think of <<- as equivalent to assign (if you set the inherits parameter in that function to TRUE). The benefit of assign is that it allows you to specify more parameters (e.g. the environment), so I prefer to use assign over <<- in most cases.
Using <<- and assign(x, value, inherits=TRUE) means that "enclosing environments of the supplied environment are searched until the variable 'x' is encountered." In other words, it will keep going through the environments in order until it finds a variable with that name, and it will assign it to that. This can be within the scope of a function, or in the global environment.
In order to understand what these functions do, you need to also understand R environments (e.g. using search).
I regularly use these functions when I'm running a large simulation and I want to save intermediate results. This allows you to create the object outside the scope of the given function or apply loop. That's very helpful, especially if you have any concern about a large loop ending unexpectedly (e.g. a database disconnection), in which case you could lose everything in the process. This would be equivalent to writing your results out to a database or file during a long running process, except that it's storing the results within the R environment instead.
My primary warning with this: be careful because you're now working with global variables, especially when using <<-. That means that you can end up with situations where a function is using an object value from the environment, when you expected it to be using one that was supplied as a parameter. This is one of the main things that functional programming tries to avoid (see side effects). I avoid this problem by assigning my values to a unique variable names (using paste with a set or unique parameters) that are never used within the function, but just used for caching and in case I need to recover later on (or do some meta-analysis on the intermediate results).
One place where I used <<- was in simple GUIs using tcl/tk. Some of the initial examples have it -- as you need to make a distinction between local and global variables for statefullness. See for example
library(tcltk)
demo(tkdensity)
which uses <<-. Otherwise I concur with Marek :) -- a Google search can help.
On this subject I'd like to point out that the <<- operator will behave strangely when applied (incorrectly) within a for loop (there may be other cases too). Given the following code:
fortest <- function() {
mySum <- 0
for (i in c(1, 2, 3)) {
mySum <<- mySum + i
}
mySum
}
you might expect that the function would return the expected sum, 6, but instead it returns 0, with a global variable mySum being created and assigned the value 3. I can't fully explain what is going on here but certainly the body of a for loop is not a new scope 'level'. Instead, it seems that R looks outside of the fortest function, can't find a mySum variable to assign to, so creates one and assigns the value 1, the first time through the loop. On subsequent iterations, the RHS in the assignment must be referring to the (unchanged) inner mySum variable whereas the LHS refers to the global variable. Therefore each iteration overwrites the value of the global variable to that iteration's value of i, hence it has the value 3 on exit from the function.
Hope this helps someone - this stumped me for a couple of hours today! (BTW, just replace <<- with <- and the function works as expected).
f <- function(n, x0) {x <- x0; replicate(n, (function(){x <<- x+rnorm(1)})())}
plot(f(1000,0),typ="l")
The <<- operator can also be useful for Reference Classes when writing Reference Methods. For example:
myRFclass <- setRefClass(Class = "RF",
fields = list(A = "numeric",
B = "numeric",
C = function() A + B))
myRFclass$methods(show = function() cat("A =", A, "B =", B, "C =",C))
myRFclass$methods(changeA = function() A <<- A*B) # note the <<-
obj1 <- myRFclass(A = 2, B = 3)
obj1
# A = 2 B = 3 C = 5
obj1$changeA()
obj1
# A = 6 B = 3 C = 9
I use it in order to change inside map() an object in the global environment.
a = c(1,0,0,1,0,0,0,0)
Say I want to obtain a vector which is c(1,2,3,1,2,3,4,5), that is if there is a 1, let it 1, otherwise add 1 until the next 1.
map(
.x = seq(1,(length(a))),
.f = function(x) {
a[x] <<- ifelse(a[x]==1, a[x], a[x-1]+1)
})
a
[1] 1 2 3 1 2 3 4 5
I have a function in R that structures my raw data. I create a dataframe called output and then want to make a dynamic variable name depending on the function value block.
The output object does contain a dataframe as I want, and to rename it dynamically, at the end of the function I do this (within the function):
a = assign(paste("output", block, sep=""), output)
... but after running the function there is no object output1 (if block = 1). I simply cannot retrieve the output object, neither merely output nor the dynamic output1 version.
I tried this then:
a = assign(paste("output", block, sep=""), output)
return(a)
... but still - no success.
How can I retrieve the dynamic output variable? Where is my mistake?
Environments.
assign will by default create a variable in the environment in which it's called. Read about environments here: http://adv-r.had.co.nz/Environments.html
I assume you're doing something like:
foo <- function(x){ assign("b", x); b}
If you run foo(5), you'll see it returns 5 as expected (implying that b was created successfully somewhere), but b won't exist in your current environment.
If, however, you do something like this
foo <- function(x){ assign("b", x, envir=parent.frame()); b}
Here, you're assigning not to the current environment at the time assign is called (which happens to be foo's environment). Instead, you're assigning into the parent environment (which, since you're calling this function directly, will be your environment).
All this complexity should reveal to you that this will be fairly complex, a nightmare to maintain, and a really bad idea from a maintenance perspective. You'd surely be better off with something like:
foo <- function(x) { return(x) };
b <- foo(5)
Or if you need multiple items returned:
foo <- function(x) { return(list(df=data.frame(col1=x), b=x)) }
results <- foo(5)
df <- results$df
b <- results$b
But ours is not to reason why...
I am minimizing this function below using the optim function, which works really well. My only problem is that I can't save the W matrix, I am computing inside the function when minimizing. Is there a way to save the W matrix somehow?
W<-c()
GMM_1_stage <- function(beta) {for (i in 1:(nrow(gmm_i))){
gmm_i[i,]=g_beta(i,beta)}
gmm_N=t(colSums(gmm_i))%*%colSums(gmm_i)
W<-solve((1/(nrow(A)/5))*t(gmm_i)%*%gmm_i)
return(gmm_N)
}
GMM_1<-optim(beta_MLE,GMM_1_stage)
Best regards
Here is a safer version of #mrip's answer that uses a temporary environment rather than <<-:
tempenv <- new.env()
tempenv$xx <- c()
fun<-function(x){
tempenv$xx[ length(tempenv$xx) + 1 ] <- x
x^2
}
optimize(fun,c(-1,1))
tempenv$xx
By using the temporary environment you don't need to worry about accidentally writing over an object in the global environment or <<- assigning in an unexpected place.
You can assign to an object in the global environment (or in a the closest ancestor environment where the variable is defined) using <<-. So, for example, if I wanted to keep track of every value of x during a simple optimization I could do this.
xx<-c()
fun<-function(x){
xx[length(xx)+1]<<-x
x^2
}
optimize(fun,c(-1,1))
xx
## [1] -2.360680e-01 2.360680e-01 5.278640e-01 -2.775558e-17 4.069010e-05
## [6] -4.069010e-05 -2.775558e-17
In your case, if you only want the last value of W you can replace that line in your code with:
W<<-solve((1/(nrow(A)/5))*t(gmm_i)%*%gmm_i)
If you want them all, then first set Wlist<-list(), and then in your function set
Wlist[[length(Wlist)+1]]<<-solve((1/(nrow(A)/5))*t(gmm_i)%*%gmm_i)
My question
If an object x is passed to a function f that modifies it R will create a modified local copy of x within f's environment, rather than changing the original object (due to the copy-on-change principle). However, I have a situation where x is very big and not needed once it has been passed to f, so I want to avoid storing the original copy of x once f is called. Is there a clever way to achieve this?
f is an unknown function to be supplied by a possibly not very clever user.
My current solution
The best I have so far is to wrap x in a function forget that makes a new local reference to x called y, removes the original reference in the workspace, and then passes on the new reference. The problem is that I am not certain it accomplish what I want and it only works in globalenv(), which is a deal breaker in my current case.
forget <- function(x){
y <- x
# x and y now refers to the same object, which has not yet been copied
print(tracemem(y))
rm(list=deparse(substitute(x)), envir=globalenv())
# The outside reference is now removed so modifying `y`
# should no longer result in a copy (other than the
# intermediate copy produced in the assigment)
y
}
f <- function(x){
print(tracemem(x))
x[2] <- 9000.1
x
}
Here is an example of calling the above function.
> a <- 1:3
> tracemem(a)
[1] "<0x2ac1028>"
> b <- f(forget(a))
[1] "<0x2ac1028>"
[1] "<0x2ac1028>"
tracemem[0x2ac1028 -> 0x2ac1e78]: f
tracemem[0x2ac1e78 -> 0x308f7a0]: f
> tracemem(b)
[1] "<0x308f7a0>"
> b
[1] 1.0 9000.1 3.0
> a
Error: object 'a' not found
Bottom line
Am I doing what I hope I am doing and is there a better way to do it?
(1) Environments You can use environments for that:
e <- new.env()
e$x <- 1:3
f <- function(e) with(e, x <- x + 1)
f(e)
e$x
(2) Reference Classes or since reference classes automatically use environments use those:
E <- setRefClass("E", fields = "x",
methods = list(
f = function() x <<- x + 1
)
)
e <- E$new(x = 1:3)
e$f()
e$x
(3) proto objects also use environments:
library(proto)
p <- proto(x = 1:3, f = function(.) with(., x <- x + 1))
p$f()
p$x
ADDED: proto solution
UPDATED: Changed function name to f for consistency with question.
I think the easiest approach is to only load the working copy into memory, instead of loading both the original (global namespace) and the working copy (function namespace). You can sidestep your whole issue by using the 'ff' package to define your 'x' and 'y' data sets as 'ffdf' data frames. As I understand it, 'ffdf' data frames reside on disk and load into memory only as parts of the data frame are needed and purge when those parts are no longer necessary. This would mean, theoretically, that the data would be loaded into memory to copy into the function namespace and then purged after the copy was complete.
I'll admit that I rarely have to use the 'ff' package, and when I do, I usually don't have any issues at all. I'm not checking specific memory usage, though, and my goal is usually just to perform a large calculation across the data. It works, and I don't ask questions.