【问题标题】:Given an R dataframe with column A, how do I create two new columns containing all ordered combinations of A给定一个带有 A 列的 R 数据框,如何创建两个包含 A 的所有有序组合的新列
【发布时间】:2011-09-25 11:30:31
【问题描述】:

我有一个带有一个 id 列(下面的 x)和许多变量(下面的 y1,y2)的 data.frame。

    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 数据操作,但这个让我很难过。对单行全能答案以及更具可读性的教学答案表示敬意。

【问题讨论】:

  • 我也希望看到一个单行。 :-)
  • 接受挑战。发布了使用基础 R 的单线解决方案。

标签: r dataframe data-manipulation


【解决方案1】:

好吧,它远不及单线(我有点怀疑这是可能的),但这是一种“幼稚”的方法:

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]])
}

我没有命名列,但事后很容易做到。

不是很优雅,但也许可以让你开始......

【讨论】:

  • 不错。但是单线确实是可能的。看我的回答。
【解决方案2】:

我不确定你到底想要什么,但据我了解,这可能接近你想要的:

> 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

如果您提供更详细的信息,也许您可​​以获得更好的答案。

【讨论】:

    【解决方案3】:

    这行得通(也许除了订单)

    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") )
    

    但我真的不明白这一点

    【讨论】:

    • +1 啊哈。我看到我们都使用combn 来生成组合。但是您可以使用标准子集并 cbind 结果,而不是嵌套merge
    【解决方案4】:

    两行是我能做的最好的,并且仍然保持明智:(编辑:参见答案底部的一行。)

    创建一些数据:

    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"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-28
      • 2018-12-20
      • 1970-01-01
      • 2022-01-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多