2010-10-12 7 views
12

Ich habe zwei data.frames mit jeweils drei Spalten: chrom, start & Stop, nennen wir sie RangesA und RangesB. Ich suche für jede Zeile von RangesA, welche (wenn überhaupt) Zeile in RangesB vollständig die RangesA Zeile enthält - womit ich meine rangesAChrom == rangesBChrom, rangesAStart >= rangesBStart and rangesAStop <= rangesBStop.Suche nach Überlappungen in Bereichen mit R

Im Moment mache ich folgendes, was ich einfach nicht sehr mag. Beachten Sie, dass ich aus anderen Gründen über die Reihen von RangesA hinauslaufe, aber keiner dieser Gründe wird wahrscheinlich eine große Sache sein, es bringt nur dazu, dass die Dinge angesichts dieser speziellen Lösung lesbarer werden.

rangesA:

chrom start stop 
5  100  105 
1  200  250 
9  275  300 

rangesB:

chrom start stop 
    1  200  265 
    5  99  106 
    9  275  290 

für jede Zeile in rangesA:

matches <- which((rangesB[,'chrom'] == rangesA[row,'chrom']) && 
       (rangesB[,'start'] <= rangesA[row, 'start']) && 
       (rangesB[,'stop'] >= rangesA[row, 'stop'])) 

ich dort Figur muss einen besseren (und besser sein, ich meine, schneller über große Instanzen von RangesA und RangesB), dies zu tun, als über dieses Konstrukt zu schleifen. Irgendwelche Ideen?

Antwort

13

Dies wäre viel einfacher/schneller, wenn Sie die beiden Objekte zuerst zusammenführen können.

ranges <- merge(rangesA,rangesB,by="chrom",suffixes=c("A","B")) 
ranges[with(ranges, startB <= startA & stopB >= stopA),] 
# chrom startA stopA startB stopB 
#1  1 200 250 200 265 
#2  5 100 105  99 106 
2

Für Ihre Beispieldaten:

rangesA <- data.frame(
    chrom = c(5, 1, 9), 
    start = c(100, 200, 275), 
    stop = c(105, 250, 300) 
) 
rangesB <- data.frame(
    chrom = c(1, 5, 9), 
    start = c(200, 99, 275), 
    stop = c(265, 106, 290) 
) 

Dies wird es tun mit sapply, so dass jede Spalte in rangesA eine Zeile und jede Zeile wird entsprechende Zeile in rangesB:

> sapply(rangesA$stop, '>=', rangesB$start) & sapply(rangesA$start, '<=', rangesB$stop) 
     [,1] [,2] [,3] 
[1,] FALSE TRUE FALSE 
[2,] TRUE FALSE FALSE 
[3,] FALSE FALSE TRUE 
18

Verwenden Sie die IRanges/GenomicRanges-Pakete von Bioconductor, die speziell für diese Probleme entwickelt wurden (und massiv skalieren)

source("http://bioconductor.org/biocLite.R") 
biocLite("IRanges") 

wenige geeignete Behälter für die Bereiche auf unterschiedlichen Chromosomen Es gibt, ist ein RangesList

library(IRanges) 
rangesA <- split(IRanges(rangesA$start, rangesA$stop), rangesA$chrom) 
rangesB <- split(IRanges(rangesB$start, rangesB$stop), rangesB$chrom) 
#which rangesB wholly contain at least one rangesA? 
ov <- countOverlaps(rangesB, rangesA, type="within")>0 
+1

Gut Zeiger auf IRanges, vergaß darüber. Ich ging damit nicht weiter, da es aus vielerlei Gründen nicht zu meiner eigenen Situation passte, aber immer noch gut zu wissen. Mein Spielzeugbeispiel hat ein paar Schlüsselbits (meine eigene Schuld) weggelassen, die das Arbeiten mit IRanges schwierig für mich machten, und die merge() Lösung lieferte eine massive Beschleunigung, wie es war. Während es massiv skaliert, sehen wir auch viele sehr kleine Fälle und was ich vermute, war, dass der Overhead des S4 es in diesen Fällen verlangsamte. – geoffjentry

+1

gibt es eh auch teilüberlappungen zu zählen? – Cina

2

RangesA und RangesB sind deutlich BETT Syntax, kann dies außerhalb R in der Befehlszeile mit bedtools, extrem schnell erfolgen und flexibel mit einem Dutzend anderer Optionen, um mit genomischen Intervallen zu arbeiten. Dann legen die Ergebnisse wieder in R.

https://code.google.com/p/bedtools/

9

Die data.table Paket hat eine Funktion, die foverlaps() der Zusammenführung über Intervallbereiche da V1.9.4 Lage ist:

require(data.table) 
setDT(rangesA) 
setDT(rangesB) 

setkey(rangesB) 
foverlaps(rangesA, rangesB, type="within", nomatch=0L) 
# chrom start stop i.start i.stop 
# 1:  5 99 106  100 105 
# 2:  1 200 265  200 250 
  • setDT() konvertiert data.frame to data.table durch Referenz

  • setkey() sortiert die data.table nach den angegebenen Spalten (in diesem Fall alle Spalten, da wir keine Spalten angegeben haben) und markiert diese Spalten als sortiert, die wir später für die Verknüpfung verwenden.

  • foverlaps() verbindet sich die Überlappung effizient. Eine ausführliche Erläuterung und einen Vergleich mit anderen Ansätzen finden Sie unter this answer.

1

Ich füge die dplyr Lösung hinzu.

library(dplyr) 
inner_join(rangesA, rangesB, by="chrom") %>% 
    filter(start.y < start.x | stop.y > stop.x) 

Ausgang:

chrom start.x stop.x start.y stop.y 
1  5  100 105  99 106 
2  1  200 250  200 265 
+0

Stellen Sie sich eine Situation vor, in der BereicheA 20k Zeilen haben und BereicheB 300k Zeilen haben -> insanse riesige Verknüpfung -> unmöglich, in R RAM Speicher zu passen. Lösungen mit IRanges sind besser –

+0

IRanges funktionierte nicht für das OP. Siehe oben. – Joe