2017-01-19 6 views
3

I ont une data.frame avec début et de fin:rangées Collapse avec des plages de chevauchement

ranges<- data.frame(start = c(65.72000,65.72187, 65.94312,73.75625,89.61625),stop = c(79.72187,79.72375,79.94312,87.75625,104.94062)) 

> ranges 
    start  stop 
1 65.72000 79.72187 
2 65.72187 79.72375 
3 65.94312 79.94312 
4 73.75625 87.75625 
5 89.61625 104.94062 

Dans cet exemple, les plages de la rangée 2 et 3 sont entièrement à l'intérieur de la plage comprise entre « début » sur la ligne 1 et arrêter le couloir 4. Ainsi, le chevauchement des gammes 1-4 doit être replié à une gamme:

> ranges 
    start  stop 
1 65.72000 87.75625 
5 89.61625 104.94062 

I essayé ceci:

mdat <- outer(ranges$start, ranges$stop, function(x,y) y > x) 
mdat[upper.tri(mdat)|col(mdat)==row(mdat)] <- NA 
mdat 

A nd maintenant je dois juste comprendre comment combiner tous les vrais, mais pas sûr que ce soit la meilleure façon d'aller

+0

ne semble pas trop facile. Avez-vous déjà regardé dplyr? Serait mon premier essai à résoudre. – Rockbar

+0

J'ai essayé ceci: 'mdat <- externe (range $ start, range $ stop, fonction (x, y) y> x) mdat [supérieur.tri (mdat) | col (mdat) == row (mdat)] <- NA mdat' Et maintenant j'ai juste besoin de comprendre comment combiner tous les vrais, mais je ne sais pas si c'est la meilleure façon d'aller – Liza

+0

qu'est-ce que vous définissez comme se chevauchant? – MJH

Répondre

6

Vous pouvez essayer ceci:

library(dplyr) 
ranges %>% 
     arrange(start) %>% 
     group_by(g = cumsum(cummax(lag(stop, default = first(stop))) < start)) %>% 
     summarise(start = first(start), stop = max(stop)) 

# A tibble: 2 × 3 
#  g start  stop 
# <int> <dbl>  <dbl> 
#1  0 65.72000 87.75625 
#2  1 89.61625 104.94062 
4

Voici une solution data.table

library(data.table) 
setDT(ranges) 
ranges[, .(start=min(start), stop=max(stop)), 
     by=.(group=cumsum(c(1, tail(start, -1) > head(stop, -1))))] 
    group start  stop 
1:  1 65.72000 87.75625 
2:  2 89.61625 104.94062 

Ici, les groupes sont construits en vérifiant si le début précédent est supérieur à l'arrêt, puis en utilisant cumsum. dans chaque groupe, le minimum de démarrage et le maximum d'arrêt sont calculés.

2

Avec base R et melt/unstack, ajoutons quelques autres dates pour rendre le problème plus intéressant et générique:

ranges<- data.frame(start = c(65.72000,65.72187, 65.94312,73.75625,89.61625,105.1,104.99),stop = c(79.72187,79.72375,79.94312,87.75625,104.94062,110.22,108.01)) 
ranges 
#  start  stop 
#1 65.72000 79.72187 
#2 65.72187 79.72375 
#3 65.94312 79.94312 
#4 73.75625 87.75625 
#5 89.61625 104.94062 
#6 105.10000 110.22000 
#7 104.99000 108.01000 

library(reshape2) 
ranges <- melt(ranges) 
ranges <- ranges[order(ranges$value),] 
ranges 
# variable  value 
#1  start 65.72000 
#2  start 65.72187 
#3  start 65.94312 
#4  start 73.75625 
#8  stop 79.72187 
#9  stop 79.72375 
#10  stop 79.94312 
#11  stop 87.75625 
#5  start 89.61625 
#12  stop 104.94062 
#7  start 104.99000 
#6  start 105.10000 
#14  stop 108.01000 
#13  stop 110.22000 

Maintenant, comme on peut le voir ci-dessus, (avec une hypothèse raisonnable que nous avons une valeur de départ c'est le plus petit de toutes les valeurs et une valeur d'arrêt qui est la plus grande de toutes les valeurs), le problème se réduit à trouver le motif stop suivi d'un start en rangées consécutives et qui seront les seuls points d'intérêt pour nous (trouver les plages de chevauchement) en dehors de la première et de la dernière rangée. Le code suivant réalise que:

indices <- intersect(which(ranges$variable=='start')-1, which(ranges$variable=='stop')) 
unstack(ranges[c(1, sort(c(indices, indices+1)), nrow(ranges)),], value~variable) 
#  start  stop 
#1 65.72000 87.75625 
#2 89.61625 104.94062 
#3 104.99000 110.22000