From luke-tierney at uiowa.edu  Thu Jan 15 20:43:07 2015
From: luke-tierney at uiowa.edu (luke-tierney at uiowa.edu)
Date: Thu, 15 Jan 2015 13:43:07 -0600
Subject: [Rd] Closing over Garbage
In-Reply-To: <B9BB7576-E6AB-4733-ABEB-6353FEBC81A1@sigg-iten.ch>
References: <B9BB7576-E6AB-4733-ABEB-6353FEBC81A1@sigg-iten.ch>
Message-ID: <alpine.LFD.2.11.1501151337560.20538@itasca.stat.uiowa.edu>

On Thu, 15 Jan 2015, Christian Sigg wrote:

> Given a large data.frame, a function trains a series of models by looping over two steps:
>
> 1. Create a model-specific subset of the complete training data
> 2. Train a model on the subset data
>
> The function returns a list of trained models which are later used for prediction on test data.
>
> Due to how models and closures work in R, each model contains a lot of data that is not necessary for prediction. The space requirements of all models combined can become prohibitive if the number of samples in the training data and the number of models is sufficiently large:
>
> 1. A trained linear model (and other models that follow the same conventions) contains the training data itself and related quantities (such as residuals). While this is convenient for some kinds of analysis, it negates the space saving effect of compacting the training data into the model parameters.
>
> 2. Any function created in the loop contains the training data in its enclosing environment. For example, a linearising transform defined as
>
> linearise <- function(x) {
>    x^gamma
> }
>
> (where gamma is derived from the training data) does not only contain `gamma` but other objects in its enclosing environment as well (e.g. intermediate computations in the loop). If `linearise` is returned with the model, those objects are also returned implicitly.
>
> The first point can be dealt with by removing those components of the model which are not necessary for prediction (e.g. model$residuals <- NULL). For the second point, more work and care is needed to clean up all enclosing environments of created functions (not only `linearise` but also model$terms etc.).
>
> I have read that V8's garbage collector avoids this problem by distinguishing between local and context variables
>
> https://stackoverflow.com/questions/5326300/garbage-collection-with-node-js
>
> Can something similar be done in R? Is there a programming technique that is less tedious than "manual" cleanup of all enclosing environments?

R's semantics do not permit this sort of optimization in general --
there may be something we could do if users could provide annotations
that allow the semantics to be relaxed; that sort of thing is being
considered but won't be available anytime soon.

The approach I use in situations like this is to write top-level
functions that create closures. So for your example, replace

  linearise <- function(x) {
     x^gamma
  }

with

  makeLinearize(x, gamma),

where makeLinearize is defined at top level as

makeLinearize <- function(x, gamma) {
     function(x) {
         x^gamma
     }
}

Best,

luke

>
> Thanks,
> Christian
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

-- 
Luke Tierney
Ralph E. Wareham Professor of Mathematical Sciences
University of Iowa                  Phone:             319-335-3386
Department of Statistics and        Fax:               319-335-3017
    Actuarial Science
241 Schaeffer Hall                  email:   luke-tierney at uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu



[Rd] Closing over Garbage
luke-tierney at uiowa.edu