按相似行折叠数据框

collapse dataframe by similar rows

我想折叠以下数据框

df

chr start    stop        gain loss pvalue_gain pvalue_loss
6 68838806   68857819    0    6    1.00000000  0.05105438
9 29779560   29788411    5    1    0.02320654  1.00000000
9 29788411   29809428    5    1    0.02320654  1.00000000
9 29809428   29831788    5    1    0.02320654  1.00000000
9 29831788   29899917    4    1    0.05145798  1.00000000
10   650294    727180    7    0    0.07759025  1.00000000

我想折叠每个字符,其中连续行的增益、损失、pvalue_gain 和 pvalue_loss 数字相同。但是,对于折叠数据框时的这些连续行,我想使用这些连续行的第一行的起始编号和这些连续行的最后一个停止编号。

例如-

chr start    stop        gain loss pvalue_gain pvalue_loss
9 29779560   29788411    5    1    0.02320654  1.00000000
9 29788411   29809428    5    1    0.02320654  1.00000000
9 29809428   29831788    5    1    0.02320654  1.00000000

将折叠为

chr start    stop        gain loss pvalue_gain pvalue_loss
9 29779560   29831788    5    1    0.02320654  1.00000000

最终输出:

chr start    stop        gain loss pvalue_gain pvalue_loss
6 68838806   68857819    0    6    1.00000000  0.05105438
9 29779560   29831788    5    1    0.02320654  1.00000000
9 29831788   29899917    4    1    0.05145798  1.00000000
10   650294    727180    7    0    0.07759025  1.00000000

我不确定如何使用聚合函数执行此操作,希望得到任何帮助。谢谢!

你可以试试

library(data.table)
setDT(df)[,list(chr=chr[1], start=start[1], stop=stop[.N]) ,
                 by=list(gain, loss, pvalue_gain, pvalue_loss)]

或使用dplyr

library(dplyr)
df %>% 
   group_by(gain, loss, pvalue_gain, pvalue_loss) %>% 
   summarise(chr=chr[1], start=start[1], stop=stop[n()])

更新

根据@Michael Lawrence 关于非重叠匹配的评论,纠正此问题的一种方法是:

setDT(df)[, .ind:= cumsum(c(TRUE,start[-1]!=stop[-.N])),
        list(gain, loss, pvalue_gain, pvalue_loss)][,
       list(chr=chr[1], start=start[1], stop=stop[.N]),
       list(gain, loss, pvalue_gain, pvalue_loss, .ind)][,.ind:=NULL][]
#    gain loss pvalue_gain pvalue_loss chr    start     stop
#1:    0    6       1.000       0.051   6 68838806 68857819
#2:    5    1       0.023       1.000   9 29779560 29831788
#3:    5    1       0.023       1.000   9 29831815 29831841
#4:    4    1       0.051       1.000   9 29831788 29899917
#5:    7    0       0.078       1.000  10   650294   727180

新数据

df <- structure(list(chr = c(6L, 9L, 9L, 9L, 9L, 9L, 10L), start = 
c(68838806L, 29779560L, 29788411L, 29809428L, 29831815L, 29831788L, 650294L
), stop = c(68857819L, 29788411L, 29809428L, 29831788L, 29831841L, 
29899917L, 727180L), gain = c(0L, 5L, 5L, 5L, 5L, 4L, 7L), loss = c(6L, 
1L, 1L, 1L, 1L, 1L, 0L), pvalue_gain = c(1, 0.02320654, 0.02320654, 
0.02320654, 0.02320654, 0.05145798, 0.07759025), pvalue_loss = c(0.05105438, 
1, 1, 1, 1, 1, 1)), .Names = c("chr", "start", "stop", "gain", 
"loss", "pvalue_gain", "pvalue_loss"), class = "data.frame", row.names = c(NA, 
-7L))

您可以使用 data.table 包中的 unique 并进行一些修改:

library(data.table)
unique(as.data.table(df)[, stop := stop[.N], 
                           key = .(gain, loss, pvalue_gain, pvalue_loss)])

#    chr    start     stop gain loss pvalue_gain pvalue_loss
# 1:   6 68838806 68857819    0    6  1.00000000  0.05105438
# 2:   9 29831788 29899917    4    1  0.05145798  1.00000000
# 3:   9 29779560 29831788    5    1  0.02320654  1.00000000
# 4:  10   650294   727180    7    0  0.07759025  1.00000000

由于您有基因组拷贝数数据,您可能会考虑使用来自 Bioconductor 的 GenomicRanges 包。您可以定义一个名为 GRanges 的对象,它正式表示数据的语义,因此能够为典型用例提供方便高效的功能。

这里我们构造GRanges对象:

gr <- makeGRangesFromDataFrame(df)

现在我认为你真正想做的是只要拷贝数相同就减少相邻范围。所以我们只需要按拷贝数值对数据进行分组:

grl <- split(gr, as.list(df[c("gain", "loss", "pvalue_gain", "pvalue_loss")]))

由于方法包中的错误,as.list 是必需的。无论如何,我们然后减少相邻的范围并结转值:

reduced <- unlist(reduce(grl))
values(reduced) <- values(unlist(phead(grl, 1L)))

最后一行有点复杂。如果 GRangesList 记得它是如何拆分的就更好了。现在正在努力。