[R] expand.grid without expanding

From: Luís Torgo <ltorgo_at_liacc.up.pt>
Date: Thu 09 Feb 2006 - 05:08:40 EST

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)


> 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')))
[1] -1

[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.


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@liacc.up.pt
    4050-190 PORTO - PORTUGAL        WWW   : http://www.liacc.up.pt/~ltorgo

R-help@stat.math.ethz.ch mailing list
PLEASE do read the posting guide! http://www.R-project.org/posting-guide.html
Received on Thu Feb 09 06:45:32 2006

This archive was generated by hypermail 2.1.8 : Fri 03 Mar 2006 - 03:42:26 EST