R에서 두 가지 더 많은 기준으로 겹치는 시간 간격을 식별합니까?


10

중복 / 중복 된 항목에 대해 더 오랜 기간 동안 이루어진 조류 관찰을 확인해야합니다.

다른 지점 (A, B, C)의 관찰자들은 관찰하여 종이지도에 표시했습니다. 종, 관측점 및 시간 간격에 대한 추가 데이터가 포함 된 선 특징으로 가져온 선.

일반적으로 관찰자는 관찰하면서 전화를 통해 서로 통신하지만 때로는 잊어 버려서 중복 선을 얻습니다.

이미 원을 터치하는 선으로 데이터를 줄 였으므로 공간 분석을 할 필요는 없지만 각 종의 시간 간격 만 비교하면 비교에서 찾은 것과 동일한 개체라는 것을 확신 할 수 있습니다 .

이제 R에서 다음과 같은 항목을 식별하는 방법을 찾고 있습니다.

  • 같은 날에 겹치는 간격으로 만들어집니다.
  • 그리고 같은 종인 곳
  • 서로 다른 관측점 (A 또는 B 또는 C 또는 ...)으로 만들어졌습니다.

여기에 이미지 설명을 입력하십시오

이 예에서는 동일한 개인의 중복 항목을 수동으로 발견했습니다. 관찰 지점이 다르고 (A <-> B), 종은 동일하며 (Sst) 시작 및 종료 시간 간격이 겹칩니다.

여기에 이미지 설명을 입력하십시오

이제 data.frame에 새 필드 "중복"을 만들어 두 행 모두에 내보낼 수있는 공통 ID를 제공하고 나중에 수행 할 작업을 결정합니다.

이미 사용 가능한 솔루션을 많이 검색했지만 종에 대한 프로세스를 하위 집합 (바람직하게는 루프 제외)으로 설정하고 2 + x 관측점에 대한 행을 비교해야한다는 사실에 대해서는 찾지 못했습니다.

놀아야 할 데이터 :

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")

예를 들어 https : //.com/q/25815032에서 언급 한 data.table 함수 foverlaps를 사용하여 부분 솔루션을 찾았습니다.

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)

물론, 이것은 어떻게 든 "작동"하지만, 실제로 내가 결국 달성하고자하는 것은 아닙니다.

먼저 관측점을 하드 코딩해야합니다. 임의의 수의 포인트를 취하는 솔루션을 찾고 싶습니다.

둘째, 결과는 실제로 쉽게 작업을 재개 할 수있는 형식이 아닙니다. 일치하는 행은 실제로 같은 행에 배치되지만 목표는 행을 아래에 배치하고 새 열에 공통 식별자를 갖는 것입니다.

셋째, 간격이 세 지점 모두에서 겹치는 경우 수동으로 다시 확인해야합니다 (내 데이터에는 해당되지 않지만 일반적으로 가능합니다)

결국, 나는 그룹 ID로 식별 가능한 모든 후보자와 함께 새로운 data.frame을 수신하고 싶습니다.

그래서 더 많은 아이디어를 얻는 방법이 있습니까?


나는 완전히 이해하고 있지는 않지만 PostgreSQL에서 상당히 직설적 인 작업처럼 보입니다. 시간 범위에 대한 기능이 있습니다. 내가 알기로는 PostgreSQL의와 R. 사이의 공유 데이터에 쉽게해야합니다
니클라스 따방

나는 Postgres에 대한 지식이 전혀 없다는 것을 인정해야하지만 실제로 저녁에 맥주를 마실 때 일부 SQL 제품을 사용할 수 있다는 생각도했습니다. 나머지 작업에서는 데이터 세트와 관련이 있지만 R은 도구이지만 R은 일부 패키지를 통해 SQL 기능도 수행 할 수 있음을 알고 있습니다. 조사 중 ....
Bernd V.

수백, 수천, 수백만 행의 데이터 집합이 얼마나 큽니까? SQL 함수의 경우 sqldf 를 찾았 습니까 ?
Simbamangu

한편, 나는 해결책을 찾았습니다. 수치심 나는 ​​지금까지 그것을 게시하지 않았다. 다른 사람들이 사용하기 위해 더 일반적으로 만들어야 할 것입니다. 그런 다음 최대한 빨리 게시하겠습니다.
Bernd V.

모두 벡터화되고 for루프를 사용하지 않으면 +1합니다 !
Simbamangu

답변:


1

일부 의견 제시 자들이 언급했듯이 SQL은 복잡한 제약 조건을 표현하기에 좋은 옵션입니다. sqldf의 패키지는 쉽게 관계형 데이터베이스를 직접 설정할 필요없이 R에서 SQL의 전력을 사용 할 수 있습니다.

다음은 SQL을 사용하는 솔루션입니다. 실행하기 전에, 나는에 데이터의 간격 열 이름을 변경했다 startTimeendTime이름이 있기 때문에 fromSQL에 예약되어 있습니다.

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)

이해를 돕기 위해 SQL 응답 dupes_wide은 다음과 같이 보입니다.

                         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_1120_1430_B_4
1E8316DBF631BBF6D2CCBD15A85E6EF3 20150812_0907_1208_A_5 20150812_0900_1225_B_6

자체 조인 FROM testdata x JOIN testdata y : 단일 데이터 집합에서 행 쌍을 찾는 것은 자체 조인입니다. 모든 행을 다른 행과 비교해야합니다. 이 ON표현식에는 쌍을 유지하기위한 제약 조건이 나열되어 있습니다.

겹치는 간격 :이 SQL ( source )에 사용 된 겹침의 정의가 foverlaps당신을 위해하고있는 것과 다르다는 것을 확신 합니다. "군내"유형을 사용했는데, 이는 이전 obsPoint에 관측치가 나중에 관측치 내에 있어야한다는 것을 요구합니다 obsPoint(그러나 C 의 관측치가 완전히 B 내에있는 경우에는 반대입니다 ). 운 좋게도 다른 중첩 정의를 인코딩해야하는 경우 SQL에서 쉽게 수행 할 수 있습니다.

다른 점들 : 다른 관측점들로부터 복제가 만들어 졌다는 당신의 제약은 실제로 표현 될 것 (x.obsPoint <> y.obsPoint)입니다. 내가 입력하면 SQL은 각 행에서 새가 순서를 바꾼 것처럼 모든 중복 쌍을 두 번 반환합니다. 대신 나는 <고유 한 절반의 행만 유지하기 위해를 사용했습니다 . (이것이 유일한 방법은 아닙니다)

고유 중복 ID : 이전 솔루션과 마찬가지로 SQL 자체는 동일한 행에 중복을 나열합니다. SQLite에서 각 쌍의 고유 ID를 생성 hex(randomblob(16))하는 해킹 ( 그러나 권장 ) 방법입니다.

출력 형식 : 동일한 행의 복제본이 마음에 들지 않아 melt분할 merge하여 복제 한 ID를 초기 데이터 프레임에 다시 할당합니다.

제한 사항 : 내 솔루션은 동일한 조류가 두 개 이상의 트랙 에서 캡처되는 경우를 처리하지 못합니다 . 더 까다 롭고 다소 잘못 정의되어 있습니다. 예를 들어 시간 범위가 다음과 같은 경우

    |-Bird1-|
             |-Bird2-|
                      |-Bird3-|

다음 Bird1은 의 중복 Bird2 의 중복, Bird3은 되지만 Bird1Bird3 중복?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.