Учитывая фреймворк R с столбцом A, как мне создать два новых столбца, содержащих все упорядоченные комбинации A

У меня есть data.frame с одним столбцом id (x ниже) и рядом переменных (y1, y2 ниже).

x y1 y2
1 1 43 55
2 2 51 53
[...]

То, что я хотел бы сгенерировать из этого, - это кадр данных, в котором первые два столбца охватывают каждую упорядоченную комбинацию x (кроме того, где они равны) вместе с столбцами для каждой переменной, связанной с порядком. Заголовок кадра данных и первые две строки будут выглядеть так (это делалось вручную, извинялись):

xi xj y1i y1j y2i y2j
 1 2 43 51 55 53
 2 1 51 43 53 55
[...]

Таким образом, каждая строка будет содержать источник и пункт назначения (i и j), а затем значения для y1 в каждом источнике и получателе.

Я медленно изучаю манипуляции с данными R, но это меня толкает. Престижность для одной строки все-таки ответит, а также более читаемый дидактический ответ.

4 ответа

Это работает (возможно, по порядку)

firstdf <- data.frame(x = c( 1, 2, 4, 5), 
 y1 = c(43,51,57,49), y2 = c(55,53,47,44)) 
co <- combn(firstdf$x,2)
seconddf <- data.frame(xi = c(co[1,], co[2,]), xj = c(co[2,], co[1,]))
thirddf <- merge(merge(seconddf, firstdf, by.x = "xj", by.y = "x" ),
 firstdf, by.x = "xi", by.y = "x", suffixes = c("j", "i") )

для создания

> thirddf
 xi xj y1j y2j y1i y2i
1 1 2 51 53 43 55
2 1 5 49 44 43 55
3 1 4 57 47 43 55
4 2 4 57 47 51 53
5 2 1 43 55 51 53
6 2 5 49 44 51 53
7 4 5 49 44 57 47
8 4 1 43 55 57 47
9 4 2 51 53 57 47
10 5 1 43 55 49 44
11 5 2 51 53 49 44
12 5 4 57 47 49 44

где первая и пятая строки соответствуют вашему примеру.

Если вы берете firstdf как указано и настаиваете на одной строке, вы можете включить его в

merge(merge(data.frame(xi = c(combn(firstdf$x,2)[1,], combn(firstdf$x,2)[2,]), xj = c(combn(firstdf$x,2)[2,], combn(firstdf$x,2)[1,])), firstdf, by.x = "xj", by.y = "x" ), firstdf, by.x = "xi", by.y = "x", suffixes = c("j", "i") )

но я действительно не вижу точки


Две строки - это лучшее, что я могу сделать, и все еще держу это разумно: ( Изменить: см. нижнюю часть ответа для одного слоя).

Создайте несколько данных:

n <- 4
a <- cbind(x=LETTERS[1:n], y=letters[1:n])
a
 x y 
[1,] "A" "a"
[2,] "B" "b"
[3,] "C" "c"
[4,] "D" "d"

Код:

f <- function(x, i){cbind(i, x[i[,1],], x[i[,2],])}
f(a, t(combn(seq_len(nrow(a)), 2)))

Результаты:

x y x y 
[1,] "1" "2" "A" "a" "B" "b"
[2,] "1" "3" "A" "a" "C" "c"
[3,] "1" "4" "A" "a" "D" "d"
[4,] "2" "3" "B" "b" "C" "c"
[5,] "2" "4" "B" "b" "D" "d"
[6,] "3" "4" "C" "c" "D" "d"

ИЗМЕНИТЬ

Это можно превратить в однострочный, используя анонимные функции:

(function(x, i=t(combn(seq_len(nrow(a)), 2))){cbind(i, x[i[,1],], x[i[,2],])})(a)
 x y x y 
[1,] "1" "2" "A" "a" "B" "b"
[2,] "1" "3" "A" "a" "C" "c"
[3,] "1" "4" "A" "a" "D" "d"
[4,] "2" "3" "B" "b" "C" "c"
[5,] "2" "4" "B" "b" "D" "d"
[6,] "3" "4" "C" "c" "D" "d"


Я не уверен, что вы точно хотите в целом, но насколько я понимаю, это может быть близко к тому, что вы хотите:

> library(combinat) # for permn
> library(plyr) # for llply
> 
> # sample data
> d <- data.frame(x = 1:3, y1 = rnorm(3), y2 = rnorm(3))
> d
 x y1 y2
1 1 -0.17525893 -1.1660321
2 2 -0.05585689 -0.2059244
3 3 0.90500983 -1.3067601
> 
> # permutation of rows
> idx <- permn(nrow(d))
> idx
[[1]]
[1] 1 2 3
... snip ...
[[6]]
[1] 2 1 3
> 
> # a list of perm-ed data.frame
> d2 <- llply(idx, function(i)data.frame(idx = 1:nrow(d), d[i,]))
> d2
[[1]]
 idx x y1 y2
1 1 1 -0.17525893 -1.1660321
2 2 2 -0.05585689 -0.2059244
3 3 3 0.90500983 -1.3067601
... snip ...
[[6]]
 idx x y1 y2
2 1 2 -0.05585689 -0.2059244
1 2 1 -0.17525893 -1.1660321
3 3 3 0.90500983 -1.3067601
> 
> # merge htam
> d3 <- subset(Reduce(function(df1, df2) merge(df1, df2, by="idx"), d2), select = -c(idx))
> d3
 x.x y1.x y2.x x.y y1.y y2.y x.x.1 y1.x.1 y2.x.1 x.y.1 y1.y.1 y2.y.1 x.x.2 y1.x.2 y2.x.2 x.y.2
1 1 -0.17525893 -1.1660321 1 -0.17525893 -1.1660321 3 0.90500983 -1.3067601 3 0.90500983 -1.3067601 2 -0.05585689 -0.2059244 2
2 2 -0.05585689 -0.2059244 3 0.90500983 -1.3067601 1 -0.17525893 -1.1660321 2 -0.05585689 -0.2059244 3 0.90500983 -1.3067601 1
3 3 0.90500983 -1.3067601 2 -0.05585689 -0.2059244 2 -0.05585689 -0.2059244 1 -0.17525893 -1.1660321 1 -0.17525893 -1.1660321 3
 y1.y.2 y2.y.2
1 -0.05585689 -0.2059244
2 -0.17525893 -1.1660321
3 0.90500983 -1.3067601
> 
> # and here is the one-liner version
> subset(Reduce(function(df1, df2) merge(df1, df2, by="idx"), llply(permn(nrow(d)), function(i)data.frame(idx=1:nrow(d), d[i,]))), select=-c(idx))
 x.x y1.x y2.x x.y y1.y y2.y x.x.1 y1.x.1 y2.x.1 x.y.1 y1.y.1 y2.y.1 x.x.2 y1.x.2 y2.x.2 x.y.2
1 1 -0.17525893 -1.1660321 1 -0.17525893 -1.1660321 3 0.90500983 -1.3067601 3 0.90500983 -1.3067601 2 -0.05585689 -0.2059244 2
2 2 -0.05585689 -0.2059244 3 0.90500983 -1.3067601 1 -0.17525893 -1.1660321 2 -0.05585689 -0.2059244 3 0.90500983 -1.3067601 1
3 3 0.90500983 -1.3067601 2 -0.05585689 -0.2059244 2 -0.05585689 -0.2059244 1 -0.17525893 -1.1660321 1 -0.17525893 -1.1660321 3
 y1.y.2 y2.y.2
1 -0.05585689 -0.2059244
2 -0.17525893 -1.1660321
3 0.90500983 -1.3067601

Если вы предоставите информацию более подробно, вероятно, вы сможете получить более качественные ответы.


Ну, это нигде близко к однострочному (что я вроде сомневаюсь), но здесь "наивный" подход:

dat <- data.frame(x=1:5,y1=6:10,y2=11:15)
#Collect all ordered pairs of elements of x
tmp <- expand.grid(dat$x,dat$x)
tmp <- tmp[tmp[,1] != tmp[,2],]
#Init a matrix to hold the results
rs <- as.matrix(cbind(tmp,matrix(NA,nrow(tmp),4)))
#Loop through each ordered pair
for (i in 1:nrow(rs)){
 rs[i,3:6] <- c(dat$y1[rs[i,1:2]],dat$y2[rs[i,1:2]])
}

Я не назвал столбцы, но это легко сделать после факта.

Не очень элегантный, но, возможно, что-то, чтобы вы начали...

licensed under cc by-sa 3.0 with attribution.