在 R 中总结几列数据的整洁方法?

Tidy way to summarize several columns of data in R?

我有一个包含转录本 ID 及其相关基因名称的大型数据框,还有一个列指示某个模型是否报告 gene/transcript 具有重要意义。每个转录本总是与一个基因相关联,尽管每个基因都与多个转录本相关联。这是一个可重现的例子:

transcript <- c('t1', 't2', 't3', 't4', 't5', 't6', 't7','t8', 't9', 't10')
gene <- c('g1', 'g1', 'g1', 'g2', 'g2', 'g2', 'g3','g3', 'g3', 'g3')
model1 <- c('TRUE', 'TRUE', 'TRUE', 'FALSE', 'FALSE', 'FALSE', 'TRUE', 'TRUE', 'TRUE', 'TRUE')
model2 <-c('FALSE', 'FALSE', 'FALSE', 'TRUE', 'TRUE', 'TRUE', 'TRUE', 'TRUE', 'TRUE', 'TRUE')
shared <- data.frame(transcript, gene, model1, model2)
shared

transcript gene model1 model2
<chr> <chr> <chr> <chr>
t1  g1  TRUE    FALSE   
t2  g1  TRUE    FALSE   
t3  g1  TRUE    FALSE   
t4  g2  FALSE   TRUE    
t5  g2  FALSE   TRUE    
t6  g2  FALSE   TRUE    
t7  g3  TRUE    TRUE    
t8  g3  TRUE    TRUE    
t9  g3  TRUE    TRUE    
t10 g3  TRUE    TRUE

我想通过 TRUE 值的数量和身份将这个 df 压缩和总结成这样的东西:

n_transcripts n_genes transcripts genes
<dbl> <dbl> <chr> <chr>
model1  7   2   t1;t2;t3;t7;t8;t9;t10   g1;g3
model2  7   2   t4;t5;t6;t7;t8;t9;t10   g2;g3

我已经尝试创建一个空白 df 并从初始 df 进行总结,但在区分 model1 和 model2 时一直受阻。实际上,我有几十个模型,我想避免手动检查每个模型。有人知道从哪里开始吗?

在模型列上转换为更长的格式,并仅过滤值为 TRUE 的那些行。按型号分组并汇总想要的值。

shared %>%
  pivot_longer(
    cols = matches("^model[0-9]+$"),
    names_to = "model"
  ) %>%
  filter(value == TRUE) %>%
  group_by(model) %>%
  summarise(
    n_transcripts = n(),
    n_genes = length(unique(gene)),
    transcripts = str_c(unique(transcript), collapse = ";"),
    genes = str_c(unique(gene), collapse = ";"),
  )

这是我的方法。

我的方法是使用包 dplyr,它擅长像这样总结数据。但是,当您的数据采用整齐的形式时效果最好,这意味着它是完美的正方形并且每一列都是一个变量。这意味着“model1”和“model2”两列必须合而为一,如下所示:

require(dplyr)

shared <- shared %>% 
  gather(., key = "model", value = "expr", -c(1:2))

这会将 model1 和 model2 行放在彼此之上,并将它们的结果 TRUE/FALSE 放入它们自己的变量中,我在这里称之为 expr

您的数据现在确实有更多行,但现在汇总起来要容易得多,因为我们可以在“模型”列上使用 dplyr::group_by() 并对其余部分求和。首先,我们必须解决一些其他问题。

在您的数据中,您的 TRUE/FALSE 值是“字符”值,而不是逻辑值。这意味着 R 将这些值理解为名称,而不是 yes/no、0/1 或其他任何东西。当我们要计算这些时,我将它们更改为这样的值:

shared[shared == "TRUE"] <- 1
shared[shared == "FALSE"] <- 0

shared$expr <- as.numeric(shared$expr)

像我在这里做的那样强制 expr 类型为 as.numeric() 是必要的,因为它又变成了“字符”。这可能是我的侥幸。

不管怎样,我们现在准备总结一下。如果您不熟悉 dplyr,那么接下来的部分可能会让人感到困惑:

shared <- shared %>% 
  .[.$expr == 1, ] %>%  #Remove the rows with FALSE (0)
  group_by(model) %>% 
  summarize(n_transcripts = sum(expr), #Sum all the TRUE (1)
            n_genes = length(unique(gene)), #Count unique genes
            transcripts = paste(unique(transcript), collapse = ";"), 
            genes = paste(unique(gene), collapse = ";"))

这里发生了很多事情,dplyr 让我们可以一口气完成所有这些事情。我正在使用 %>%(管道)运算符将每个函数的结果传递给下一个函数。 this function/call 的真正内容是函数 summarize(),它将 count/paste/tally “model”列中每个唯一值的数据,在本例中为“model1”和“model2”