[R] expand.grid without expanding

Luís Torgo ltorgo at liacc.up.pt
Wed Feb 8 19:08:40 CET 2006


Dear list,
I've recently came across a problem that I think I've solved and that I wanted 
to share with you for two reasons:
- Maybe others come across the same problem.
- Maybe someone has a much simpler solution that wants to share with me ;-)

The problem is as follows: expand.grid() allows you to generate a data.frame 
with all combinations of a set of values, e.g.:
> expand.grid(par1=-1:1,par2=c('a','b'))
  par1 par2
1   -1    a
2    0    a
3    1    a
4   -1    b
5    0    b
6    1    b

There is nothing wrong with this nice function except when you have too many 
combinations to fit in your computer memory, and that was my problem: I 
wanted to do something for each combination of a set of variants, but this 
set was to large for storing in memory in a data.frame generated by 
expand.grid. A possible solution would be to have a set of nested for() 
cycles but I preferred a solution that involved a single for() cycle going 
from 1 to the number of combinations and then at each iteration having some 
form of generating the combination "i". And this was the "real problem": how 
to generate a function that picks the same style of arguments as 
expand.grid() and provides me with the values corresponding to line "i" of 
the data frame that would have been created bu expand.grid(). For instance, 
if I wanted the line 4 of the above call to expand.grid() I should get the 
same as doing:
> expand.grid(par1=-1:1,par2=c('a','b'))[4,]
  par1 par2
4   -1    b

but obviously without having to use expand.grid() as that involves generating 
a data frame that in my case wouldn't fit in the memory of my computer.

Now, the function I've created was the following:
--------------------------------------------
getVariant <- function(id,vars) {

  if (!is.list(vars)) stop('vars needs to be a list!')

  nv <- length(vars)

  lims <- sapply(vars,length)
  if (id > prod(lims)) stop('id above the number of combinations!')
  
  res <- vector("list",nv)

  for(i in nv:2) {

    f <- prod(lims[1:(i-1)])
    
    res[[i]] <- vars[[i]][ceiling(id / f)]

    id <- id - (ceiling(id/f)-1)*f
  }

  res[[1]] <- vars[[1]][id]
  names(res) <- names(vars)
  res

}
--------------------------------------
> expand.grid(par1=-1:1,par2=c('a','b'))[4,]
  par1 par2
4   -1    b
> getVariant(4,list(par1=-1:1,par2=c('a','b')))
$par1
[1] -1

$par2
[1] "b"

I would be glad to know if somebody came across the same problem and has a 
better suggestion on how to solve this.

Thanks,
Luis

-- 
Luis Torgo
    FEP/LIACC, University of Porto   Phone : (+351) 22 339 20 93
    Machine Learning Group           Fax   : (+351) 22 339 20 99
    R. de Ceuta, 118, 6o             email : ltorgo at liacc.up.pt
    4050-190 PORTO - PORTUGAL        WWW   : http://www.liacc.up.pt/~ltorgo




More information about the R-help mailing list