Spacedman
Spacedman

Reputation: 94192

A more generalized expand.grid function?

expand.grid(a,b,c) produces all the combinations of the values in a,b, and c in a matrix - essentially filling the volume of a three-dimensional cube. What I want is a way of getting slices or lines out of that cube (or higher dimensional structure) centred on the cube.

So, given that a,b, c are all odd-length vectors (so they have a centre), and in this case let's say they are of length 5. My hypothetical slice.grid function:

slice.grid(a,b,c,dimension=1)

returns a matrix of the coordinates of points along the three central lines. Almost equivalent to:

rbind(expand.grid(a[3],b,c[3]),
      expand.grid(a,b[3],c[3]),
      expand.grid(a[3],b[3],c))

almost, because it has the centre point repeated three times. Furthermore:

slice.grid(a,b,c,dimension=2)

should return a matrix equivalent to:

rbind(expand.grid(a,b,c[3]), expand.grid(a,b[3],c), expand.grid(a[3],b,c))

which is the three intersecting axis-aligned planes (with repeated points in the matrix at the intersections).

And then:

slice.grid(a,b,c,dimension=3)

is the same as expand.grid(a,b,c).

This isn't so bad with three parameters, but ideally I'd like to do this with N parameters passed to the function expand.grid(a,b,c,d,e,f,dimension=4) - its unlikely I'd ever want dimension greater than 3 though.

It could be done by doing expand.grid and then extracting those points that are required, but I'm not sure how to build that criterion. And I always have the feeling that this function exists tucked in some package somewhere...

[Edit] Right, I think I have the criterion figured out now - its to do with how many times the central value appears in each row. If its less than or equal to your dimension+1...

But generating the full matrix gets big quickly. It'll do for now.

Upvotes: 5

Views: 1998

Answers (1)

G. Grothendieck
G. Grothendieck

Reputation: 269624

Assuming a, b and c each have length 3 (and if there are 4 variables then they each have length 4 and so on) try this. It works by using 1:3 in place of each of a, b and c and then counting how many 3's are in each row. If there are four variables then it uses 1:4 and counts how many 4's are in each row, etc. It uses this for the index to select out the appropriate rows from expand.grid(a, b, c) :

slice.expand <- function(..., dimension = 1) {
    L <- lapply(list(...), seq_along)
        n <- length(L)
    ix <- rowSums(do.call(expand.grid, L) == n) >= (n-dimension)
    expand.grid(...)[ix, ]
}

# test
a <- b <- c <- LETTERS[1:3]
slice.expand(a, b, c, dimension = 1)
slice.expand(a, b, c, dimension = 2)
slice.expand(a, b, c, dimension = 3)

Upvotes: 1

Related Questions