Question: I have a dataframe with around 30k observations, divided in 300 groups. For example

```
id, group, x, y
1,  1,     2, 3
2,  1,     4, 3
3,  1,     2, 4
4,  2,     5, 4
5,  2,     5, 3
6,  2,     6, 4

```

I want to make it so

```
pair, group, x_i, x_j, y_i, y_j
12,   1,     2,   4,   3,   3
13,   1,     2,   2,   3,   4
23,   1,     4,   2,   3,   4
45,   2,     5,   5,   4,   3

```

and so on. I've found a few topics, but they don't seem to apply exactly to my problem.

Answer: 
The `combn` function can be used to generate each corresponding pair of `x` and `y` values. We operate by `group` using `lapply`. `lapply` returns a list so we use `rbind` to put each list element (the results for each `group`) back together in a single data frame.

```
new.dat = lapply(unique(dat$group), function(g) {
  data.frame(pairs = apply(t(combn(dat$id[dat$group==g], 2)), 1, paste, collapse=""),
             group=g,
             x = t(combn(dat$x[dat$group==g], 2)),
             y = t(combn(dat$y[dat$group==g], 2)))
})

do.call(rbind, new.dat)

```

> 
> 
> ```
>   pairs group x.1 x.2 y.1 y.2
> 1    12     1   2   4   3   3
> 2    13     1   2   2   3   4
> 3    23     1   4   2   3   4
> 4    45     2   5   5   4   3
> 5    46     2   5   6   4   4
> 6    56     2   5   6   3   4
> 
> ```
> 
> 

You could also use `split`, which saves some typing, but is about 10% slower on my machine:

```
lapply(split(dat, dat$group), function(df) {
  data.frame(pairs = apply(t(combn(df$id, 2)), 1, paste, collapse=""),
             group=g,
             x = t(combn(df$x, 2)),
             y = t(combn(df$y, 2)))
})

```
I won't say this is an ooptimal result, but it should work:

```
df <- read.table(text="id, group, x, y
1,1,2,3
2,1,4,3
3,1,2,4
4,2,5,4
5,2,5,3
6,2,6,4", header=T, sep=",")

df.new <- do.call(rbind,lapply(tapply(df$id, df$group, combn, m=2), FUN=function(x) data.frame(pairi=x[1,], pairj=x[2,])))
df.new <- do.call(rbind,apply(df.new, 1, FUN=function(x) data.frame(pair=paste0(x[1], x[2]),group=df[df$id==x[1], 'group'], x_i=df[df$id==x[1],'x'], x_j=df[df$id==x[2],'x'], y_i=df[df$id==x[1],'y'], y_j=df[df$id==x[2],'y'] )))
df.new
    pair group x_i x_j y_i y_j
1.1   12     1   2   4   3   3
1.2   13     1   2   2   3   4
1.3   23     1   4   2   3   4
2.1   45     2   5   5   4   3
2.2   46     2   5   6   4   4
2.3   56     2   5   6   3   4

```