Eu tenho que verificar as observações das aves feitas durante um período mais longo para entradas duplicadas / sobrepostas.
Observadores de diferentes pontos (A, B, C) fizeram observações e as marcaram em mapas em papel. Essas linhas foram trazidas para uma linha com dados adicionais para as espécies, o ponto de observação e os intervalos de tempo em que foram vistos.
Normalmente, os observadores se comunicam por telefone enquanto observam, mas às vezes esquecem, então eu recebo essas linhas duplicadas.
Eu já reduzi os dados para as linhas que tocam o círculo, então não preciso fazer uma análise espacial, mas apenas comparar os intervalos de tempo para cada espécie e ter certeza de que é o mesmo indivíduo encontrado pela comparação .
Agora estou procurando uma maneira em R para identificar as entradas que:
- são feitas no mesmo dia com um intervalo de sobreposição
- e onde é a mesma espécie
- e que foram feitas a partir de diferentes pontos de observação (A ou B ou C ou ...))
Neste exemplo, encontrei manualmente entradas possivelmente duplicadas do mesmo indivíduo. O ponto de observação é diferente (A <-> B), a espécie é a mesma (Sst) e o intervalo dos horários de início e término se sobrepõe.
Agora, eu criaria um novo campo "duplicado" no meu data.frame, fornecendo às duas linhas um ID comum para poder exportá-las e depois decidir o que fazer.
Procurei muitas soluções já disponíveis, mas não encontrei nenhuma sobre o fato de que eu tenho que sub-definir o processo para as espécies (de preferência sem loop) e tenho que comparar as linhas para 2 + x pontos de observação.
Alguns dados para brincar:
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_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"
), obsPoint = c("A", "A", "A", "A", "C", "B", "B", "B", "B",
"B", "A", "A", "A", "B", "B", "B", "A", "A", "A", "A"), species = 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"), class = "factor"),
from = structure(c(1436687150, 1436689710, 1436691420, 1436694850,
1437992160, 1437991500, 1437995580, 1437992360, 1437995960,
1437998360, 1437992100, 1437994000, 1437995340, 1439366410,
1439369600, 1439374980, 1439367240, 1439367540, 1439369760,
1439370720), class = c("POSIXct", "POSIXt"), tzone = ""),
to = structure(c(1436687690, 1436690230, 1436691690, 1436694970,
1437992320, 1437992200, 1437995600, 1437992400, 1437996070,
1437998750, 1437992230, 1437994220, 1437996780, 1439366570,
1439370070, 1439375070, 1439367410, 1439367820, 1439369930,
1439370830), class = c("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"), class = "data.frame")
Encontrei uma solução parcial com os foverlaps da função data.table mencionados, por exemplo, aqui https://stackoverflow.com/q/25815032
library(data.table)
#Subsetting the data for each observation point and converting them into data.tables
A <- setDT(testdata[testdata$obsPoint=="A",])
B <- setDT(testdata[testdata$obsPoint=="B",])
C <- setDT(testdata[testdata$obsPoint=="C",])
#Set a key for these subsets (whatever key exactly means. Don't care as long as it works ;) )
setkey(A,species,from,to)
setkey(B,species,from,to)
setkey(C,species,from,to)
#Generate the match results for each obsPoint/species combination with an overlapping interval
matchesAB <- 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)
Claro, isso de alguma forma "funciona", mas realmente não é o que eu gosto de alcançar no final.
Primeiro, eu tenho que codificar os pontos de observação. Eu preferiria encontrar uma solução com um número arbitrário de pontos.
Segundo, o resultado não está em um formato com o qual eu possa realmente continuar trabalhando com facilidade. As linhas correspondentes são na verdade colocadas na mesma linha, enquanto meu objetivo é que as linhas sejam colocadas por baixo e, em uma nova coluna, elas teriam um identificador comum.
Terceiro, tenho que verificar manualmente novamente, se um intervalo se sobrepuser aos três pontos (o que não é o caso dos meus dados, mas geralmente poderia)
No final, eu gostaria de receber um novo data.frame com todos os candidatos identificáveis por um ID de grupo que eu possa associar de volta às linhas e exportar o resultado como uma camada para uma análise mais aprofundada.
Então, alguém mais ideias de como fazer isso?
for
loops!