【问题标题】:Many binary columns: need to reduce to fewer binary columns using grouping information in a second dataframe许多二进制列:需要使用第二个数据帧中的分组信息减少到更少的二进制列
【发布时间】:2021-05-17 19:05:05
【问题描述】:

我有两个数据框。我试图在一个中使用信息来减少另一个中的二进制列的数量。 df1 是一些样本数据,其中 var 是基因变异的存在或不存在,ID = 个体。

df1 <- data.frame(ID = c(1, 2, 3, 4, 5, 6), 
                  var1 = c(1, 1, 0, 0, 1, 0),
                  var2 = c(1, 0, 0, 0, 1, 0),
                  var3 = c(0, 0, 0, 1, 0, 1),
                  var4 = c(0, 0, 1, 0, 0, 0))

df2 是将基因变体更新为更一般的类别。这里,var1 和 var2 归类在一起(gen = 1),var3 和 var4 归类在一起(gen = 2)。

df2<-data.frame(ID = c('var1','var2','var3','var4'),
                gen = c(1,1,2,2))

我希望我的最终数据表显示这些更通用的基因变异类别的存在或不存在,如下所示:

df3<-data.frame(ID = c(1, 2, 3, 4, 5, 6), 
                var1 = c(1, 1, 0, 0, 1, 0),
                var2 = c(1, 0, 0, 0, 1, 0),
                var3 = c(0, 0, 0, 1, 0, 1),
                var4 = c(0, 0, 1, 0, 0, 0),
                gen1 = c(1,1,0,0,1,0),
                gen2 = c(0,0,1,1,0,1))
> df3
  ID var1 var2 var3 var4 gen1 gen2
1  1    1    1    0    0    1    0
2  2    1    0    0    0    1    0
3  3    0    0    0    1    0    1
4  4    0    0    1    0    0    1
5  5    1    1    0    0    1    0
6  6    0    0    1    0    0    1

我知道一定有办法解决这个问题,但我就是想不通。 任何建议将不胜感激。谢谢。

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    我们可以使用tidyverse

    library(dplyr)
    library(tidyr)
    library(stringr)
    df1 %>% 
      pivot_longer(cols = -ID) %>%
      left_join(df2, by = c('name' = 'ID')) %>%
      group_by(ID, gen) %>%
      summarise(value = +(any(value ==1)), .groups = 'drop') %>%
      mutate(gen = str_c('gen', gen)) %>%
      pivot_wider(names_from = gen, values_from = value) %>% 
      left_join(df1, . ) %>%
      select(names(df1), everything())
    

    -输出

    #   ID var1 var2 var3 var4 gen1 gen2
    #1  1    1    1    0    0    1    0
    #2  2    1    0    0    0    1    0
    #3  3    0    0    0    1    0    1
    #4  4    0    0    1    0    0    1
    #5  5    1    1    0    0    1    0
    #6  6    0    0    1    0    0    1
    

    或使用rowSums

    df1 %>% 
     mutate(gen1 = +(rowSums(select(., df2$ID[df2$gen == 1]) > 0) > 0), 
           gen2 = +(rowSums(select(., df2$ID[df2$gen == 2]) > 0) > 0) )
    

    【讨论】:

    • 非常感谢@akrun 的快速帮助。你的解决方案奏效了,你让我免于沮丧!我赞成你的回答,但我是新手,它不会让我这样做。
    • 在这些可能的解决方案中,我最终使用了 rowSums 选项。这是因为我很容易将它应用到我的更复杂的真实数据集(并且有效)。
    【解决方案2】:

    在基础 R 中你会这样做:

    cbind(df1, gen = do.call(cbind, by(df2$ID, df2$gen, function(x)+Reduce("|", df1[x]))))
      ID var1 var2 var3 var4 gen.1 gen.2
    1  1    1    1    0    0     1     0
    2  2    1    0    0    0     1     0
    3  3    0    0    0    1     0     1
    4  4    0    0    1    0     0     1
    5  5    1    1    0    0     1     0
    6  6    0    0    1    0     0     1
    

    你也可以这样做:

    cbind(df1, gen = +sapply(split.default(df1[-1], df2$gen), Reduce, f = "|"))
    
      ID var1 var2 var3 var4 gen.1 gen.2
    1  1    1    1    0    0     1     0
    2  2    1    0    0    0     1     0
    3  3    0    0    0    1     0     1
    4  4    0    0    1    0     0     1
    5  5    1    1    0    0     1     0
    6  6    0    0    1    0     0     1
    

    【讨论】:

    • 非常感谢@Onyambu 的快速帮助。你的解决方案奏效了,你让我免于沮丧!我赞成你的回答,但我是新手,它不会让我这样做。
    猜你喜欢
    • 2017-01-09
    • 2021-03-05
    • 1970-01-01
    • 2020-08-27
    • 2021-02-10
    • 2017-10-15
    • 1970-01-01
    • 1970-01-01
    • 2018-05-26
    相关资源
    最近更新 更多