2013-06-06 100 views
8

我試圖找到一種方法來摺疊具有相交範圍的行,用「開始」和「停止」列表示,並將摺疊值記錄到新列中。例如,我有這個數據幀:在R中摺疊相交區域

my.df<- data.frame(chrom=c(1,1,1,1,14,16,16), name=c("a","b","c","d","e","f","g"), start=as.numeric(c(0,70001,70203,70060, 40004, 50000872, 50000872)), stop=as.numeric(c(71200,71200,80001,71051, 42004, 50000890, 51000952))) 


chrom name start stop 
1 a  0 71200 
1 b 70001 71200 
1 c 70203 80001 
1 d 70060 71051 
14 e 40004 42004 
16 f 50000872 50000890 
16 g 50000872 51000952 

,我試圖找到重疊的範圍,並記錄在「開始」和「停止」的坍塌重疊行和摺疊的行的名稱所覆蓋的最大範圍,所以我會得到這樣的:

chrom start stop  name 
1 70001 80001 a,b,c,d 
14 40004 42004 e 
16 50000872 51000952 f,g 

我想我可以用包IRanges這樣的:

library(IRanges) 
ranges <- split(IRanges(my.df$start, my.df$stop), my.df$chrom) 

但後來我有麻煩塌陷列:我有線索d與findOvarlaps但這

ov <- findOverlaps(ranges, ranges, type="any") 

但我不認爲這是正確的。

任何幫助將不勝感激。

謝謝! -fra

+0

我編輯的文本,以反映該數據更好地加入在0開始的第一位置不管是用方法的建議CHROM 14沒有正確分組,可以請你告訴我爲什麼?謝謝! – user971102

回答

5

排序完數據後,您可以輕鬆測試間隔是否與前一個重疊,併爲每組重疊間隔分配一個標籤。 一旦你有這些標籤,你可以使用ddply來聚合數據。

d <- data.frame(
    chrom = c(1,1,1,14,16,16), 
    name = c("a","b","c","d","e","f"), 
    start = as.numeric(c(70001,70203,70060, 40004, 50000872, 50000872)), 
    stop = as.numeric(c(71200,80001,71051, 42004, 50000890, 51000952)) 
) 

# Make sure the data is sorted 
d <- d[ order(d$start), ] 

# Check if a record should be linked with the previous 
d$previous_stop <- c(NA, d$stop[-nrow(d)]) 
d$previous_stop <- cummax(ifelse(is.na(d$previous_stop),0,d$previous_stop)) 
d$new_group <- is.na(d$previous_stop) | d$start >= d$previous_stop 

# The number of the current group of records is the number of times we have switched to a new group 
d$group <- cumsum(d$new_group) 

# We can now aggregate the data 
library(plyr) 
ddply( 
    d, "group", summarize, 
    start=min(start), stop=max(stop), name=paste(name,collapse=",") 
) 
# group start  stop name 
# 1  1  0 80001 a,d,c,b 
# 2  2 50000872 51000952  e,f 

但是這忽略了chrom柱:考慮到它,你可以做同樣的事,每個染色體,分別。

d <- d[ order(d$chrom, d$start), ] 
d <- ddply(d, "chrom", function(u) { 
    x <- c(NA, u$stop[-nrow(u)]) 
    y <- ifelse(is.na(x), 0, x) 
    y <- cummax(y) 
    y[ is.na(x) ] <- NA 
    u$previous_stop <- y 
    u 
}) 
d$new_group <- is.na(d$previous_stop) | d$start >= d$previous_stop 
d$group <- cumsum(d$new_group) 
ddply( 
    d, .(chrom,group), summarize, 
    start=min(start), stop=max(stop), name=paste(name,collapse=",") 
) 
# chrom group start  stop name 
# 1  1  1  0 80001 a,c,b 
# 2 14  2 40004 42004  d 
# 3 16  3 50000872 51000952 e,f 
+0

謝謝,我也有d $ start 0,如果我把它看成是搞亂了一切,並用奇怪的方式將它分組使用這段代碼...(我只是編輯了正文以反映這種奇怪的行爲..) – user971102

+0

我的代碼只檢查記錄是否應該與前一個鏈接,而不是以前的鏈接。 這應該是固定的。 –

+0

這就像一個魅力。謝謝! – user971102

9

IRanges是一個很好的候選人這樣的工作。不需要使用chrom變量。

ir <- IRanges(my.df$start, my.df$stop) 
## I create a new grouping variable Note the use of reduce here(performance issue) 
my.df$group2 <- subjectHits(findOverlaps(ir, reduce(ir))) 
# chrom name start  stop group2 
# 1  1 a 70001 71200  2 
# 2  1 b 70203 80001  2 
# 3  1 c 70060 71051  2 
# 4 14 d 40004 42004  1 
# 5 16 e 50000872 50000890  3 
# 6 16 f 50000872 51000952  3 

新的group2變量是範圍指示符。現在,使用data.table我無法將數據轉換爲所需的輸出:

library(data.table) 
DT <- as.data.table(my.df) 
DT[, list(start=min(start),stop=max(stop), 
     name=list(name),chrom=unique(chrom)), 
       by=group2] 

# group2 start  stop name chrom 
# 1:  2 70001 80001 a,b,c  1 
# 2:  1 40004 42004  d 14 
# 3:  3 50000872 51000952 e,f 16 

PS:這裏倒塌的變量名不是字符串,但一個名單因素的。這比使用粘貼的collapased角色更高效,更易於訪問。

編輯因爲OP的說明,我會通過chrom創建組varibale。我的意思是現在爲每個染色體組調用Iranges代碼。我稍微修改你的數據,創建一組同一染色體的區間。

my.df<- data.frame(chrom=c(1,1,1,1,14,16,16), 
        name=c("a","b","c","d","e","f","g"), 
        start=as.numeric(c(0,3000,70203,70060, 40004, 50000872, 50000872)), 
        stop=as.numeric(c(1,5000,80001,71051, 42004, 50000890, 51000952))) 

library(data.table) 
DT <- as.data.table(my.df) 

## find interval for each chromsom 
DT[,group := { 
     ir <- IRanges(start, stop); 
     subjectHits(findOverlaps(ir, reduce(ir))) 
     },by=chrom] 

## Now I group by group and chrom 
DT[, list(start=min(start),stop=max(stop),name=list(name),chrom=unique(chrom)), 
    by=list(group,chrom)] 

    group chrom start  stop name chrom 
1:  1  1  0  1 a  1 
2:  2  1  3000  5000 b  1 
3:  3  1 70060 80001 c,d  1 
4:  1 14 40004 42004 e 14 
5:  1 16 50000872 51000952 f,g 16 
+0

看起來真的很好用IRanges – storaged

+0

@storaged是非常好的。要安裝它,你應該做以下'source(「http://bioconductor.org/biocLite.R」) biocLite(「IRanges」)' – agstudy

+0

我編輯了正文以反映更好的數據框,我也有啓動在0的位置,如果我申請這個,我沒有得到正確的重疊...我做錯了什麼? – user971102