![](/img/trans.png)
[英]R - populate a column for grouped entries based on conditions in subsequent rows of a data.frame
[英]R - Compare rows of data.frame (to combine based on conditions)
我从基因组范围(一条染色体,以及一个开始-结束位置)的data.frame开始。 我正在尝试合并1)相邻放置的行和2)在其他两列中共享一个值的行。 注意:我想要一种有效的方法,因为我的真实数据大于1000万行。 (如果可能,请使用data.table)
玩具数据:
DF <- data.frame(SampleID = c(1,1,1,1,1,2,2),
Chr = c(1,1,1,1,2,1,1),
Start = c(1, 101, 201, 401, 500, 1, 101),
End = c(100, 200, 300, 499, 599, 100, 200),
State = c(3,3,2,3,3,2,2)
)
DF
SampleID Chr Start End State
1: 1 1 1 100 3
2: 1 1 101 200 3
3: 1 1 201 300 2
4: 1 1 401 499 3
5: 1 2 500 501 3
6: 2 1 1 100 2
7: 2 1 101 200 2
由于行1和2相邻(1-100和101-200),并且共享SampleID
(1)和State
(3),因此可以合并。
以下内容不能合并:
State
s不匹配 State
Chr
)中有所不同 SampleID
。 Etcetera。 当我们应用所有这些时,我们就有了最终表。
FinalDF <- data.frame(SampleID = c(1,1,1,1,2),
Chr = c(1,1,1,2,1),
Start = c(1,201,401,500,1),
End = c(200,300,499,599,200),
State = c(3,2,3,3,2))
FinalDF
SampleID Chr Start End State
1 1 1 1 200 3
2 1 1 201 300 2
3 1 1 401 499 3
4 1 2 500 599 3
5 2 1 1 200 2
到目前为止,我已经尝试过使用GenomicRanges包中的reduce函数,但是它不起作用。
输出不正确
reduce(DF2)
GRanges object with 3 ranges and 0 metadata columns:
seqnames ranges strand
<Rle> <IRanges> <Rle>
[1] 1 [ 1, 300] *
[2] 1 [401, 499] *
[3] 2 [500, 501] *
-------
seqinfo: 2 sequences from an unspecified genome; no seqlengths
我试图对data.table进行操作,因为我的data.frames的行长为1000万行或更多,但还无法弄清。
以下问题是相同的(也许会更复杂),但没有解决方案。 R-根据两列的内容折叠行
library(data.table)
dt = as.data.table(DF) # or convert in place using setDT
dt[, .(Start = min(Start), End = max(End), State = State[1])
, by = .(SampleID, Chr, rleid(State),
cumsum(c(FALSE, head(End + 1, -1) < tail(Start, -1))))]
# SampleID Chr rleid cumsum Start End State
#1: 1 1 1 0 1 200 3
#2: 1 1 2 0 201 300 2
#3: 1 1 3 1 401 499 3
#4: 1 2 3 1 500 599 3
#5: 2 1 4 1 1 200 2
如果我正确解释了您想做什么,我建议采取以下措施:使用dplyr
对要分开的元数据进行分组,然后使用GenomicRanges
找出每个组中的范围(如果遇到性能问题,则可能需要避开data.frame
所需的GenomicRanges
并手动实现它以利用dyplr
与data.tables的性能)。 这是一个如何工作的示例(利用管道%>%
可以更轻松地了解正在发生的事情):
DF <- data.frame(SampleID = c(1,1,1,1,1,2,2),
Chr = c(1,1,1,1,2,1,1),
Start = c(1, 101, 201, 401, 500, 1, 101),
End = c(100, 200, 300, 499, 599, 100, 200),
State = c(3,3,2,3,3,2,2)
)
library(dplyr)
# take your data frame
DF %>%
# group it by the subsets
group_by(SampleID, Chr, State) %>%
# operate on each group
do(
# turn subset into a GRanges object
as(as.data.frame(.), "GRanges") %>%
# reducae ranges
GenomicRanges::reduce() %>%
# turn back into data frame for dplyr to stitch together
as.data.frame() %>%
# get the information you want
select(start, end, width)
) %>%
# ungroup for future operations
ungroup() %>%
# sort by what makes most sense for your set
arrange(SampleID, Chr, start)
输出:
Source: local data frame [5 x 6]
SampleID Chr State start end width
(dbl) (dbl) (dbl) (int) (int) (int)
1 1 3 1 200 200
1 1 2 201 300 100
1 1 3 401 499 99
1 2 3 500 599 100
2 1 2 1 200 200
# This code is kind of robust but it appears to get the job done
DF <- data.frame(SampleID = c(1,1,1,1,1,2,2),
Chr = c(1,1,1,1,2,1,1),
Start = c(1, 101, 201, 401, 500, 1, 101),
End = c(100, 200, 300, 499, 599, 100, 200),
State = c(3,3,2,3,3,2,2)
)
test_and_combine <- function(r1,r2) {
if (r1[,1] == r2[,1] & # check if "SampleID" column matches
r1[,2] == r2[,2] & # check if "Chr" column matches
(r1[,4] + 1) == r2[,3] & # test if Start and End are in sequence
r1[,5] == r2[,5]) # check if "State"column matches
{
# merge rows if true
DF_comb <- r1[,]
DF_comb[1,4] <- r2[,4]
}
else{
DF_comb <- NA
}
return(DF_comb)
}
# This section could rewritten to use Reduce()
DF_comb_final <- data.frame()
for(i in 1:(nrow(DF)-1)){ # loop through ever row of data.frame
DF_temp <- test_and_combine(DF[i,],DF[i+1,]) # send two rows to function
if(!any(is.na(DF_temp))){
DF_comb_final <- rbind(DF_comb_final,DF_temp)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.