【问题标题】:R - How can I generate difference of all combinations of columns in a data frameR - 如何生成数据框中所有列组合的差异
【发布时间】:2017-06-08 18:09:33
【问题描述】:

例子:

df <- data.frame(A=1:5, B=seq(0,10,2), C=seq(0,15,3))  
df  
A  B  C  
1  2  3  
2  4  6  
3  6  9  
4  8 12  
5 10 15  

我想要的是:

A B C (A-B) (A-C) (B-C)  
1 2 3 -1 -2 -1  
2 4 6 -2 -4 -2  
3 6 9 -3 -6 -3  
4 8 12 -4 -8 -4  
5 10 15 -5 -10 -5  

这是一个示例。在我的问题中,我有超过 100 列
有关如何在 R 中执行此操作的任何建议?

【问题讨论】:

  • 使用 dplyr、df %&gt;% mutate(ab = A - B, ac = A - C, bc = B - C) 或其他语法中的类似内容
  • 我不想手动写出所有列的方程。假设我有 100 列开始,那将是 4950 列。我不可能写出来
  • 您可以使用combn 的结果进行子集化,但添加那么多列通常是个坏主意;最好改成长形。

标签: r dataframe combinations


【解决方案1】:

我们可以在combn 中使用FUN 参数

combn(seq_along(df), 2, FUN = function(x) df[,x[1]]- df[,x[2]])
#     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#[1,]   -1   -2    0   -2   -1    1   -1    2    0    -2
#[2,]   -2   -4   -4   -7   -2   -2   -5    0   -3    -3
#[3,]   -3   -6   -8  -12   -3   -5   -9   -2   -6    -4
#[4,]   -4   -8  -12  -17   -4   -8  -13   -4   -9    -5
#[5,]   -5  -10  -16  -22   -5  -11  -17   -6  -12    -6

另外,combndata.frame 作为参数,所以很简单

combn(df, 2, FUN = function(x) x[,1]-x[,2])
#     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#[1,]   -1   -2    0   -2   -1    1   -1    2    0    -2
#[2,]   -2   -4   -4   -7   -2   -2   -5    0   -3    -3
#[3,]   -3   -6   -8  -12   -3   -5   -9   -2   -6    -4
#[4,]   -4   -8  -12  -17   -4   -8  -13   -4   -9    -5
#[5,]   -5  -10  -16  -22   -5  -11  -17   -6  -12    -6

数据

df <- data.frame(A=1:5, B=seq(2,10,2), C=seq(3,15,3), d=seq(1,25,5), e=seq(3,31,6))

【讨论】:

    【解决方案2】:

    给你

    df <- data.frame(A=1:5, B=seq(2,10,2), C=seq(3,15,3), d=seq(1,25,5), e=seq(3,31,6))
    
    > df
      A  B  C  d  e
    1 1  2  3  1  3
    2 2  4  6  6  9
    3 3  6  9 11 15
    4 4  8 12 16 21
    5 5 10 15 21 27
    
    z = combn(1:ncol(df),2)
    
    > z
         [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
    [1,]    1    1    1    1    2    2    2    3    3     4
    [2,]    2    3    4    5    3    4    5    4    5     5
    
    y = apply(z,2,function(x){
      df[,x[1]]-df[,x[2]]
    })
    

    结果:

    > y
         [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
    [1,]   -1   -2    0   -2   -1    1   -1    2    0    -2
    [2,]   -2   -4   -4   -7   -2   -2   -5    0   -3    -3
    [3,]   -3   -6   -8  -12   -3   -5   -9   -2   -6    -4
    [4,]   -4   -8  -12  -17   -4   -8  -13   -4   -9    -5
    [5,]   -5  -10  -16  -22   -5  -11  -17   -6  -12    -6
    

    矩阵 z 告诉你减去了哪对列

    您确实意识到,如果 df 有 100 列,那么所有组合加起来就是 4950。

    【讨论】:

    • 你真的不需要apply;你可以做df[z[1,]] - df[z[2,]]
    【解决方案3】:

    这对我有用:

    col_diff<-function(df)
    {
        dif_fn<-function(obj){return(obj[[1]]-obj[[2]])}
        tmp_fn<-function(inp_row){unlist(combn(inp_row,2,FUN=dif_fn,simplify = FALSE))}
        intres<-t(apply(df,1,tmp_fn))
        colnames(intres)<-unlist(combn(colnames(df),2,simplify = FALSE,FUN=function(obj){paste(obj[[1]],obj[[2]],sep="-")}))
        temp<-cbind(df, intres)
        return(temp)
    
    }
    

    应用于您的输入:

     df <- data.frame(A=1:5, B=seq(2,10,2), C=seq(3,15,3))  
    df
      A  B  C
    1 1  2  3
    2 2  4  6
    3 3  6  9
    4 4  8 12
    5 5 10 15
    
    col_diff(df)
       A  B  C A-B A-C B-C
    1 1  2  3  -1  -2  -1
    2 2  4  6  -2  -4  -2
    3 3  6  9  -3  -6  -3
    4 4  8 12  -4  -8  -4
    5 5 10 15  -5 -10  -5
    

    【讨论】:

    • @user3305645 是的,我想我应该将 colnames 与 cols 一起添加。 :)
    【解决方案4】:

    使用combn 生成2(在调用中指定)colnames 的所有组合

    m = data.frame(combn(colnames(df),2), stringsAsFactors = F)
    m
    #  X1 X2 X3
    #1  A  A  B
    #2  B  C  C
    
    df1 = data.frame(lapply(m, function(x) df[[x[2]]] - df[[x[1]]]))
    colnames(df1) = lapply(m, function(x) paste(x[2], x[1], sep="-"))
    cbind(df,df1)
    #  A B  C B-A C-A C-B
    #1 1 0  0  -1  -1   0
    #2 2 2  3   0   1   1
    #3 3 4  6   1   3   2
    #4 4 6  9   2   5   3
    #5 5 8 12   3   7   4
    

    【讨论】:

    • @user3305645 编辑了答案以使用 colnames 完成它!
    【解决方案5】:

    mapply:

    # the data: create the input data frame with mapply for fun
    df <- as.data.frame(mapply(function(i,j) seq(0, 5*i, j), 1:5, 1:5))  
    names(df) <- LETTERS[1:5]
    df 
    #  A  B  C  D  E
    #1 0  0  0  0  0
    #2 1  2  3  4  5
    #3 2  4  6  8 10
    #4 3  6  9 12 15
    #5 4  8 12 16 20
    #6 5 10 15 20 25
    
    # now use mapply to solve our problem
    pairs <- combn(seq_len(ncol(df)), 2) # find all possible pairs
    mapply(function(i,j)df[,i]-df[,j], pairs[1,], pairs[2,])
    #     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
    #[1,]    0    0    0    0    0    0    0    0    0     0
    #[2,]   -1   -2   -3   -4   -1   -2   -3   -1   -2    -1
    #[3,]   -2   -4   -6   -8   -2   -4   -6   -2   -4    -2
    #[4,]   -3   -6   -9  -12   -3   -6   -9   -3   -6    -3
    #[5,]   -4   -8  -12  -16   -4   -8  -12   -4   -8    -4
    #[6,]   -5  -10  -15  -20   -5  -10  -15   -5  -10    -5
    

    【讨论】:

      猜你喜欢
      • 2020-06-03
      • 2019-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-28
      • 2015-07-22
      • 1970-01-01
      相关资源
      最近更新 更多