baptiste
baptiste

Reputation: 77116

recursively split list elements

I cannot find the right incantation of Reduce, Recall, lapply to perform the following task. Consider the following function,

bisect.df <- function(d){
  n <- ncol(d)
  if(n%%2) n <- n-1 # drop one col if odd number
  ind <- sample(n)[seq.int(n/2)] # split randomly both parts

  list(first=d[, ind],
       second=d[, -ind])
}

given a data.frame, it returns a list of two children data.frames of equal ncol extracted randomly from their parent. I wish to apply this function recursively to the offsprings down to a given level, say 3 generations. I can do it trivially one generation at a time,

bisect.list <- function(l){
  unlist(lapply(l, bisect.df), recursive=FALSE)
}

but how do I call this recursively, say N=3 times?

Here's a test sample to play with

d <- data.frame(matrix(rnorm(16*5), ncol=16))
step1 <- bisect.list(list(d))
step2 <- bisect.list(step1)
step3 <- bisect.list(step2)
str(list(step1, step2, step3))

Upvotes: 3

Views: 1197

Answers (2)

Vincent Zoonekynd
Vincent Zoonekynd

Reputation: 32401

Here is a recursive solution: the idea is to add an argument that counts the number of remaining recursive calls. (But it does exactly the same thing as the loop version.)

f <- function( d, n=3 ) {
  if( is.data.frame( d ) )
    return( f( list(d), n ) )
  if( n == 0 )
    return( d )
  result <- lapply( d, bisect.df )
  result <- unlist( result, recursive=FALSE )
  result <- f( result, n-1 )
  result
}
d <- as.data.frame( t(1:20) )
f(d)

It may be easier to just take the column indices at random and build all the sub-data.frames at once.

Upvotes: 2

Justin
Justin

Reputation: 43265

bisect.list <- function(l,n){
  for(i in 1:n) {
    l <- unlist(lapply(l, bisect.df), recursive=FALSE)
  }
  return(l)
}

not sure how to do it without a loop...

Upvotes: 2

Related Questions