การระบุช่วงเวลาที่ทับซ้อนกันกับเกณฑ์อีกสองข้อใน R?


10

ฉันต้องตรวจสอบการสังเกตการณ์ของนกในระยะเวลานานขึ้นเพื่อดูรายการที่ซ้ำกัน / ทับซ้อนกัน

ผู้สังเกตการณ์จากจุดต่าง ๆ (A, B, C) ทำการสังเกตการณ์และทำเครื่องหมายไว้บนแผนที่กระดาษ เส้นเหล่านั้นซึ่งนำมาสู่คุณสมบัติเส้นที่มีข้อมูลเพิ่มเติมสำหรับสปีชีส์จุดสังเกตและช่วงเวลาที่เห็น

โดยปกติผู้สังเกตการณ์จะสื่อสารกันทางโทรศัพท์ในขณะที่สังเกต แต่บางครั้งพวกเขาก็ลืมดังนั้นฉันจึงได้เส้นที่ซ้ำกัน

ฉันลดข้อมูลลงไปเป็นเส้นเหล่านั้นซึ่งแตะวงกลมดังนั้นฉันไม่จำเป็นต้องทำการวิเคราะห์เชิงพื้นที่ แต่เพียงเปรียบเทียบช่วงเวลาสำหรับแต่ละสปีชีส์และมั่นใจได้ว่าเป็นบุคคลเดียวกันที่พบโดยการเปรียบเทียบ .

ตอนนี้ฉันกำลังมองหาวิธีใน R เพื่อระบุรายการเหล่านั้นซึ่ง:

  • จะทำในวันเดียวกันกับช่วงเวลาที่ทับซ้อนกัน
  • และมันอยู่ที่ไหนสายพันธุ์เดียวกัน
  • และซึ่งทำจากจุดสังเกตที่แตกต่างกัน (A หรือ B หรือ C หรือ ... ))

ป้อนคำอธิบายรูปภาพที่นี่

ในตัวอย่างนี้ฉันพบว่ามีรายการที่ซ้ำกันของบุคคลเดียวกัน จุดสังเกตแตกต่างกัน (A <-> B) สปีชีส์เหมือนกัน (Sst) และช่วงเวลาของการเริ่มต้นและสิ้นสุดของเวลาทับซ้อนกัน

ป้อนคำอธิบายรูปภาพที่นี่

ตอนนี้ฉันจะสร้างเขตข้อมูลใหม่ "ทำซ้ำ" ใน data.frame ของฉันโดยให้ทั้งสองแถวมีรหัสทั่วไปเพื่อที่จะสามารถส่งออกและตัดสินใจในภายหลังว่าจะทำอย่างไร

ฉันค้นหาวิธีแก้ปัญหาที่มีอยู่มากมาย แต่ไม่พบว่าเกี่ยวข้องกับความจริงที่ว่าฉันต้องเซตย่อยกระบวนการสำหรับสปีชีส์ (โดยเฉพาะอย่างยิ่งที่ไม่มีลูป) และต้องเปรียบเทียบแถวสำหรับจุดสังเกต 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")

ฉันพบวิธีแก้ปัญหาบางส่วนด้วยฟังก์ชันdata.table foverlaps ที่กล่าวถึงเช่นที่นี่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)

แน่นอนว่านี่เป็น "งาน" แต่จริงๆแล้วไม่ใช่สิ่งที่ฉันชอบที่จะประสบความสำเร็จในที่สุด

ก่อนอื่นฉันต้องเขียนโค้ดหนัก ๆ ของจุดสังเกต ฉันต้องการค้นหาวิธีแก้ปัญหาด้วยจำนวนคะแนนโดยพลการ

ประการที่สองผลลัพธ์ไม่ได้อยู่ในรูปแบบที่ฉันสามารถทำงานต่อได้อย่างง่ายดาย จริง ๆ แล้วแถวที่ตรงกันถูกวางไว้ในแถวเดียวกันในขณะที่เป้าหมายของฉันคือการวางแถวไว้ด้านล่างและในคอลัมน์ใหม่พวกเขาจะมีตัวระบุร่วมกัน

ประการที่สามฉันต้องตรวจสอบด้วยตนเองอีกครั้งหากช่วงเวลาซ้อนทับกันจากทั้งสามจุด (ซึ่งไม่ใช่กรณีของข้อมูลของฉัน แต่โดยทั่วไปสามารถทำได้)

ในท้ายที่สุดฉันต้องการรับ data.frame ใหม่กับผู้สมัครทั้งหมดที่ระบุได้โดยรหัสกลุ่มที่ฉันสามารถเข้าร่วมกลับไปที่บรรทัดและส่งออกผลลัพธ์เป็นเลเยอร์สำหรับการตรวจสอบเพิ่มเติม

ดังนั้นใครจะมีแนวคิดเพิ่มเติมวิธีการทำเช่นนี้?


ฉันไม่แน่ใจว่าฉันเข้าใจอย่างถ่องแท้ แต่ดูเหมือนว่าเป็นงานที่ตรงไปตรงมาใน PostgreSQL มีฟังก์ชั่นสำหรับช่วงเวลา ตามที่ฉันเข้าใจแล้วมันควรจะแบ่งปันข้อมูลระหว่าง PostgreSQL กับ R. ได้ง่าย
Nicklas Avén

ฉันต้องยอมรับว่าฉันไม่มีความรู้เกี่ยวกับ Postgres แต่ที่จริงแล้วเมื่อดื่มเบียร์เย็นนี้ฉันก็มีความคิดว่าบางสิ่งที่ sql อาจจะมีให้สำหรับสิ่งนี้ สำหรับการดำเนินการที่เหลือของฉันฉันต้องทำกับชุดข้อมูล R เป็นเครื่องมือ แต่ฉันรู้ว่าฟังก์ชัน sql สามารถดำเนินการได้ภายใน R ผ่านแพ็คเกจบางตัว กำลังสืบสวน ....
Bernd V.

ชุดข้อมูลมีขนาดเท่าไหร่ - หลายร้อยหลายพันล้านแถว? สำหรับฟังก์ชั่น SQL คุณพบsqldfหรือไม่?
Simbamangu

ในขณะเดียวกันฉันพบวิธีการทำงาน ความอัปยศกับฉันฉันไม่ได้โพสต์จนถึงตอนนี้ จะต้องทำให้มันเป็นเรื่องทั่วไปมากขึ้นที่จะใช้สำหรับคนอื่นแล้วฉันจะโพสต์มันโดยเร็ว
Bernd V.

+1 ถ้ามันเป็นเวกเตอร์ทั้งหมดและไม่ได้ใช้forลูป!
Simbamangu

คำตอบ:


1

เนื่องจากผู้แสดงความคิดเห็นบางคนพูดพาดพิง SQL เป็นตัวเลือกที่ดีสำหรับการแสดงข้อ จำกัด ที่ค่อนข้างซับซ้อน sqldfแพคเกจทำให้ง่ายต่อการใช้อำนาจของ SQL ใน R โดยไม่จำเป็นต้องตั้งค่าตัวเองฐานข้อมูลเชิงสัมพันธ์

นี่เป็นวิธีแก้ปัญหาโดยใช้ SQL ก่อนที่จะทำงานฉันต้องเปลี่ยนชื่อคอลัมน์ช่วงเวลาของข้อมูลของคุณstartTimeและendTimeเพราะชื่อfromสงวนไว้ใน 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)

เพื่อช่วยในการทำความเข้าใจการตอบสนอง 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 ( แหล่งที่มา ) นี้แตกต่างจากสิ่งที่คุณfoverlapsทำ คุณใช้ประเภท "ภายใน" ซึ่งจำเป็นต้องใช้การสังเกตก่อนหน้านี้obsPointเพื่อให้อยู่ในการสังเกตในภายหลังobsPoint(แต่พลาดการสนทนาเช่นถ้าการสังเกตของCอยู่ภายในBทั้งหมด) โชคดีที่มันง่ายใน SQL ถ้าคุณต้องการเข้ารหัสนิยามที่แตกต่างกันของการทับซ้อน

จุดที่แตกต่างกัน : ข้อ จำกัด (x.obsPoint <> y.obsPoint)ของคุณที่ซ้ำกันที่ทำจากจุดสังเกตที่แตกต่างกันจริงๆจะต้องแสดงออก ถ้าฉันพิมพ์มัน SQL จะคืนค่าทุกคู่ที่ซ้ำกันสองครั้งโดยที่นกเปลี่ยนลำดับในแต่ละแถว แต่ฉันใช้<เพื่อเก็บเฉพาะครึ่งหนึ่งของแถวที่ไม่ซ้ำกัน (นี่ไม่ใช่วิธีเดียวที่จะทำเช่นนี้)

รหัสซ้ำที่ไม่ซ้ำกัน : เช่นเดียวกับโซลูชันก่อนหน้าของคุณ SQL จะแสดงรายการที่ซ้ำกันในแถวเดียวกัน hex(randomblob(16))เป็นวิธีที่แฮ็ค ( ยังแนะนำ ) ใน SQLite เพื่อสร้างรหัสเฉพาะสำหรับแต่ละคู่

รูปแบบผลลัพธ์ : คุณไม่ชอบรายการที่ซ้ำกันในแถวเดียวกันดังนั้นจึงmeltแยกพวกเขาออกและmergeกำหนด ID ที่ซ้ำกันกลับไปที่เฟรมข้อมูลเริ่มต้นของคุณ

ข้อ จำกัด : ทางออกของฉันไม่ได้จัดการกับกรณีที่นกเดียวกันจะบันทึกในมากกว่าสองแทร็ค มันค่อนข้างซับซ้อนและไม่ค่อยชัดเจน ตัวอย่างเช่นหากช่วงเวลาของพวกเขาดูเหมือน

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

ดังนั้นBird1จึงเป็นข้อมูลซ้ำซ้อนของBird2ซึ่งเป็นสิ่งที่ซ้ำกันของBird3แต่Bird1และBird3ซ้ำกันหรือไม่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.