Suite

Identifier les intervalles de temps qui se chevauchent avec deux autres critères dans R ?

Identifier les intervalles de temps qui se chevauchent avec deux autres critères dans R ?


Je dois vérifier les observations d'oiseaux effectuées sur une période plus longue pour les entrées en double/chevauchement.

Des observateurs de différents points (A,B,C) ont fait des observations et les ont marquées sur des cartes papier. Ces lignes ont été rassemblées dans une caractéristique de ligne avec des données supplémentaires pour l'espèce, le point d'observation et les intervalles de temps où elles ont été observées.

Normalement, les observateurs communiquent entre eux par téléphone tout en observant, mais parfois ils oublient, alors j'obtiens ces lignes en double.

J'ai déjà réduit les données à ces lignes qui touchent le cercle, je n'ai donc pas à faire d'analyse spatiale, mais seulement à comparer les intervalles de temps pour chaque espèce et je peux être tout à fait sûr que c'est le même individu qui est trouvé par la comparaison .

Je cherche maintenant un moyen dans R d'identifier les entrées qui :

  • sont faites le même jour avec un intervalle de chevauchement
  • et où c'est la même espèce
  • et qui ont été faites à partir de différents points d'observation (A ou B ou C ou… ))

Dans cet exemple, j'ai trouvé manuellement des entrées éventuellement en double du même individu. Le point d'observation est différent (A <-> B), l'espèce est la même (Sst) et l'intervalle des heures de début et de fin se chevauche.

Je voudrais maintenant créer un nouveau champ "dupliquer" dans mon data.frame, en donnant aux deux lignes un identifiant commun pour pouvoir les exporter et décider plus tard de ce qu'il faut faire.

J'ai beaucoup cherché des solutions déjà disponibles, mais je n'en ai trouvé aucune concernant le fait que je dois sous-définir le processus pour l'espèce (de préférence sans boucle) et comparer les lignes pour 2 + x points d'observation.

Quelques données pour jouer avec :

testdata <- structure(list(bird_id = c("20150712_0810_1410_A_1", "20150712_0810_1410_A_2", "20150712_0810_1410_A_4", "20150712_0810_1410_A_7", "20150727_1115_1430_C_1", "20150727_1120_143027_B_1120", "2015430_10727_0810_1410_A_7", "20150727_1115_1430_C_1", "20150727_1120_143027_B_1120", "2015430_10727_12_0810_1410_A_7", "20150727_1115_1430_C_1", " 20150727_1120_143027_B_1120 ", " 2015 43027_B_1120_12, " 2015_B_1430_B_1120_, " 2015 , "20150727_1130_1430_A_2", "20150727_1130_1430_A_4", "20150727_1130_1430_A_5", "20150812_0900_1225_B_3", "20150812_0900_1225_B_6", "20150812_0900_1225_B_7", "20150812_0907_1208_A_2", "20150812_0907_1208_A_3", "20150812_0907_1208_A_5", "20150812_0907_1208_A_6"), obsPoint = c ( "A", "A", "A", "A", "C", "B", "B", "B", "B", "B", "A", "A", "A", "B ", "B", "B", "A", "A", "A", "A"), espèce = structure(c(11L, 11L, 11L, 11L, 10L, 11L, 10L, 11L, 11L , 11L, 11L, 10L, 11L, 11L, 11L, 11L, 11L, 11L, 11L, 11L), .Label = c("Bf", "Fia", "Grr", "Kch", "Ko", " Lm", "Rm", "Row", "Sea", "Sst", "Wsb"), classe = "facteur"), de = structure(c(1436687150, 1436689710, 1436691420, 1436694850, 1437992160, 1437991500, 1437995 580, 1437992360, 1437995960, 1437998360, 1437992100, 1437994000, 1437995340, 1439366410, 1439369600, 1439374980, 1439367240, 1439367540, 1439369760, 1439370720), classe = c("POSIXct", "tzone =t ""), , 1439367540, 1439369760, 1439370720) structure(c(1436687690, 1436690230, 1436691690, 1436694970, 1437992320, 1437992200, 1437995600, 1437992400, 1437996070, 1437998750, 1437992230, 1437994220, 1437996780, 1439366570, 1439382070, 1439, 143970830), classe POSIXct", "POSIXt"), tzone = "")), .Names = c("bird_id", "obsPoint", "species", "from", "to"), row.names = c("20150712_0810_1410_A_1" , "20150712_0810_1410_A_2", "20150712_0810_1410_A_4", "20150712_0810_1410_A_7", "20150727_1115_1430_C_1", "20150727_1120_1430_B_1", "20150727_1120_1430_B_2", "20150727_1120_1430_B_3", "20150727_1120_1430_B_4", "20150727_1120_1430_B_5", "20150727_1130_1430_A_2", "20150727_1130_1430_A_4", "20150727_1130_1430_A_5", " 20150812_0900_1225_B_3", "20150812_0900_1225_B_6", "20150812_0900_1225_B_7", "20150812_0907_1208_A_2", "20150812_0907_1208_A_3", "20150812_0907_1208_A_5", "20150812_0907_1208_A_6"), classe = "data.frame")

J'ai trouvé une solution partielle avec la fonction data.table chevauchements mentionné, par ex. ici https://stackoverflow.com/q/25815032

library(data.table) #Sous-ensemble des données pour chaque point d'observation et les convertir en data.tables A <- setDT(testdata[testdata$obsPoint=="A",]) B <- setDT(testdata[testdata$obsPoint= ="B",]) C <- setDT(testdata[testdata$obsPoint=="C",]) #Définir une clé pour ces sous-ensembles (quelle que soit la signification exacte de la clé. Peu importe tant que cela fonctionne ;) ) setkey(A,species,from,to) setkey(B,species,from,to) setkey(C,species,from,to) #Génère les résultats de correspondance pour chaque combinaison obsPoint/espèce avec un intervalle de chevauchement matchsAB <- foverlaps( A,B,type="within",nomatch=0L) #nomatch=0L -> remove NA matchesAC <- foverlaps(A,C,type="within",nomatch=0L) matchesBC <- foverlaps(B,C, type="within", nomatch=0L)

Bien sûr, cela "fonctionne" en quelque sorte, mais ce n'est vraiment pas ce que j'aime réaliser à la fin.

Tout d'abord, je dois coder en dur les points d'observation. Je préférerais trouver une solution en prenant un nombre arbitraire de points.

Deuxièmement, le résultat n'est pas dans un format avec lequel je peux vraiment reprendre le travail facilement. Les lignes correspondantes sont en fait placées DANS la même ligne, alors que mon objectif est de placer les lignes en dessous et dans une nouvelle colonne, elles auraient un identifiant commun.

Troisièmement, je dois vérifier à nouveau manuellement si un intervalle se chevauche à partir des trois points (ce qui n'est pas le cas avec mes données, mais pourrait généralement le faire)

En fin de compte, je voudrais juste recevoir un nouveau data.frame avec tous les candidats identifiables par un identifiant de groupe que je peux joindre aux lignes et exporter le résultat sous forme de calque pour un examen plus approfondi.

Alors, quelqu'un d'autre a-t-il une idée de comment faire ?


Comme certains commentateurs l'ont mentionné, SQL est une bonne option pour exprimer des ensembles de contraintes plutôt compliqués. Le package sqldf permet d'utiliser facilement la puissance de SQL dans R sans avoir besoin de configurer vous-même une base de données relationnelle.

Voici une solution utilisant SQL. Avant de courir, j'ai dû renommer les colonnes d'intervalle de vos données enHeure de débutetheure de finparce que le nomdeest réservé en SQL.

library(reshape2) library(sqldf) dupes_wide <- sqldf("SELECT hex(randomblob(16)) dupe_id, x.bird_id x_bird_id, y.bird_id y_bird_id FROM testdata x JOIN testdata y ON (x.startTime <= y.endTime) AND (x.endTime >= y.startTime) AND (x.species = y.species) AND (x.obsPoint < y.obsPoint)") dupes_long <- melt(dupes_wide, id.vars='dupe_id', value. name='bird_id') merge(testdata, dupes_long[, c('dupe_id', 'bird_id')], by="bird_id", all.x=TRUE)

Pour faciliter la compréhension, la réponse SQLdupes_widefinit par ressembler à ça :

dupe_id x_bird_id y_bird_id 253FCC7A58FD8401960FC5D95153356C 20150727_1130_1430_A_2 20150727_1120_1430_B_1 9C1C1A13306ECC2DF78004D421F70CE6 20150727_1130_1430_A_5 20150727_112026183BB_B_B_1 9C1C1A13306ECC2DF78004D421F70CE6 20150727_1130_1430_A_5 20150727_112026183BB_B_F 20150727_112026183BB_B_F_151285C1A13306ECC2DF78004D421F70CE6 20150727_1130_1430_A_5 20150727_112026183BB_B_F

Auto-joindreFROM testdata x JOIN testdata y: Découverte paires de lignes d'un même jeu de données est une auto-jointure. Nous devons comparer chaque ligne avec toutes les autres. LeSURexpression répertorie les contraintes de conservation des paires.

Intervalle de chevauchement: Je suis à peu près sûr que la définition de chevauchement que j'ai utilisée dans ce SQL (source) diffère de ce quechevauchementsfaisait pour toi. Vous avez utilisé le type "à l'intérieur", qui nécessite l'observation au plus tôtobsPointêtre entièrement dans l'observation au plus tardobsPoint(mais il manque l'inverse, par exemple si Cl'observation de est entièrement à l'intérieur B's). Heureusement, c'est facile en SQL si vous devez encoder une définition différente du chevauchement.

Différents points: Votre contrainte selon laquelle les doublons ont été créés à partir de différents points d'observation serait vraiment exprimée(x.obsPoint <> y.obsPoint). Si j'avais tapé cela, SQL renverrait chaque paire dupliquée deux fois, juste avec l'ordre des oiseaux dans chaque ligne. Au lieu de cela, j'ai utilisé un<pour ne garder que la moitié unique des lignes. (Ce n'est pas la seule façon de le faire)

Identifiant unique en double: Comme avec votre solution précédente, le SQL lui-même répertorie les doublons dans la même ligne.hex(randomlob(16))est un moyen piraté (mais recommandé) dans SQLite de générer des identifiants uniques pour chaque paire.

Format de sortie: Vous n'avez pas aimé les doublons dans la même rangée, alorsfondreles sépare, etfusionnerattribue les ID en double à votre bloc de données initial.

Limites: Ma solution ne gère pas le cas où le même oiseau est capturé dans plus de deux pistes. C'est plus délicat et quelque peu mal défini. Par exemple, si leurs plages horaires ressemblent à

|-- Oiseau1 --| |-- Oiseau2 --| |-- Oiseau3 --|

ensuite Oiseau1 est un doublon de Oiseau2, qui est un doublon de Oiseau3, mais sont Oiseau1 et Oiseau3 doublons ?


Voir la vidéo: Esimerkki1 tasosta