【问题标题】:Fast way to summarize a data frame across columns跨列汇总数据框的快速方法
【发布时间】:2020-01-01 01:57:48
【问题描述】:

我有五个可能的character 状态中的data.frame (genotypes):

genotypes <- c("0/0","1/1","0/1","1/0","./.")
library(dplyr)
set.seed(1)
df <- do.call(rbind, lapply(1:100, function(i)
  matrix(sample(genotypes, 30, replace = T), nrow = 1, dimnames = list(NULL, paste0("V", 1:30))))) %>%
  data.frame()

我想把每一行总结为我有多少:

  • ref.hom (0/0)
  • alt.hom (1/1)
  • het0/11/0
  • na (./.)

这似乎很慢:

sum.df <- do.call(rbind,lapply(1:nrow(df), function(i){
  data.frame(ref.hom = length(which(df[i,] == "0/0")),
             alt.hom = length(which(df[i,] == "1/1")),
             het = length(which(df[i,] == "0/1") | which(df[i,] == "1/0")),
             na = length(which(df[i,] == "./.")))
}))

还有更有效的方法,也许是基于dplyr 的方法来做到这一点?

【问题讨论】:

    标签: r dataframe dplyr bioinformatics summarize


    【解决方案1】:

    对于基因分型数据,我会使用setDT()。您将节省大量 RAM。

    library(data.table)
    df$key <- 1:nrow(df)
    df <- melt(setDT(df),id.vars = "key")
    table(df$key, df$value) 
    
     # > head(table(df$key, df$value))
     #
     #   ./. 0/0 0/1 1/0 1/1
     # 1   6   6   4   7   7
     # 2   6   3   8   5   8
     # 3   7   3   5   5  10
     # 4   4   8   1   7  10
     # 5   5   9   4   3   9
     # 6   9   2   6   8   5
    # and
    table(df$value)
    # > table(df$value)
    # ./. 0/0 0/1 1/0 1/1 
    # 620 581 601 584 614 
    

    执行时间检查:

    > time.taken.DT
    Time difference of 0.005386114 secs
    > time.taken.dplyr
    Time difference of 0.08833909 secs
    

    【讨论】:

    • 值得注意的是,setDT() 来自 data.table 包,所以人们不会想知道它是从哪里突然弹出来的。
    • 另外,如果您正在利用 data.table,您可以改用更高效的 by= 分组。
    【解决方案2】:

    在基础 R 中,您可以将 applytable 一起使用,这将返回每行中所有可能级别的计数。

    output <- t(apply(df, 1, table))
    output
    
    #     ./. 0/0 0/1 1/0 1/1
    #[1,]   7   8   4   3   8
    #[2,]   5   7   4   9   5
    #[3,]   6   5   6   5   8
    #[4,]   4   7   9   6   4
    #[5,]   6   5   6   5   8
    #[6,]   8   8   2   7   5
    #....
    

    以后如果需要,您可以将这些列合并为一层output[, 3] + output[, 4]


    另一种选择是将gather 数据转换为长格式和count

    library(dplyr)
    
    df %>%
      mutate(row = row_number()) %>%
      tidyr::gather(key, value, -row) %>%
      count(row, value)
      #If needed
      #tidyr::spread(value, n)
    

    【讨论】:

      【解决方案3】:

      dplyr,你可以试试:

      df %>%
       transmute(ref.hom = rowSums(. == "0/0"),
                 alt.hom = rowSums(. == "1/1"),
                 het = rowSums(. == "0/1") + rowSums(. == "1/0"),
                 na = rowSums(. == "./."))
      
          ref.hom alt.hom het na
      1         4      11   9  6
      2         5       2  20  3
      3         3      11  10  6
      4         5       5  15  5
      5         5       4  17  4
      6         3       8  13  6
      7         6       8  11  5
      8         4       8  11  7
      9         6       6  14  4
      10       14       8   5  3
      

      【讨论】:

      • 嗨,使用 mutate 怎么能比不使用 mutate 更快?
      • @Johannes Stötzer 说得好。我把它和另一种情况混淆了。
      猜你喜欢
      • 2011-12-05
      • 1970-01-01
      • 2015-08-11
      • 1970-01-01
      • 1970-01-01
      • 2016-12-19
      • 2020-01-30
      • 2013-01-19
      • 2020-09-08
      相关资源
      最近更新 更多