Saya harus memeriksa pengamatan burung yang dilakukan lebih lama untuk entri duplikat / tumpang tindih.
Pengamat dari berbagai titik (A, B, C) melakukan pengamatan dan menandainya di peta kertas. Garis-garis di mana dibawa ke fitur garis dengan data tambahan untuk spesies, titik pengamatan dan interval waktu mereka terlihat.
Biasanya, para pengamat berkomunikasi satu sama lain melalui telepon sambil mengamati, tetapi kadang-kadang mereka lupa, jadi saya mendapatkan garis duplikat itu.
Saya sudah mengurangi data menjadi garis-garis yang menyentuh lingkaran, jadi saya tidak perlu membuat analisis spasial, tetapi hanya membandingkan interval waktu untuk setiap spesies dan dapat yakin bahwa itu adalah individu yang sama yang ditemukan oleh perbandingan .
Saya sekarang mencari cara di R untuk mengidentifikasi entri yang:
- dibuat pada hari yang sama dengan interval yang tumpang tindih
- dan di mana itu adalah spesies yang sama
- dan yang dibuat dari titik pengamatan yang berbeda (A atau B atau C atau ...))
Dalam contoh ini, saya secara manual menemukan entri yang mungkin digandakan dari individu yang sama. Titik pengamatan berbeda (A <-> B), spesiesnya sama (Sst) dan interval waktu mulai dan akhir tumpang tindih.
Saya sekarang akan membuat bidang baru "duplikat" di data.frame saya, memberikan kedua baris id umum untuk dapat mengekspornya dan kemudian memutuskan apa yang harus dilakukan.
Saya mencari-cari banyak solusi yang sudah tersedia, tetapi tidak menemukan kenyataan bahwa saya harus mengatur ulang proses untuk spesies (lebih disukai tanpa loop) dan harus membandingkan baris untuk 2 + x titik pengamatan.
Beberapa data untuk dimainkan:
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")
Saya menemukan solusi parsial dengan fungsi data.table foverlaps yang disebutkan misalnya di sini 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)
Tentu saja, ini entah bagaimana "berhasil", tetapi sebenarnya bukan apa yang ingin saya capai pada akhirnya.
Pertama, saya harus membuat kode titik pengamatan. Saya lebih suka mencari solusi dengan mengambil sejumlah poin sembarang.
Kedua, hasilnya tidak dalam format yang saya dapat benar-benar dapat melanjutkan bekerja dengan mudah. Baris yang cocok sebenarnya dimasukkan ke dalam baris yang sama, sedangkan tujuan saya adalah membuat baris diletakkan di bawahnya, dan di kolom baru, mereka akan memiliki pengidentifikasi umum.
Ketiga, saya harus memeriksa secara manual lagi, jika interval tumpang tindih dari ketiga titik (yang tidak terjadi pada data saya, tetapi umumnya bisa)
Pada akhirnya, saya hanya ingin menerima data baru. Bingkai dengan semua kandidat yang dapat diidentifikasi oleh id grup sehingga saya dapat bergabung kembali ke garis dan mengekspor hasilnya sebagai lapisan untuk pemeriksaan lebih lanjut.
Jadi, siapa lagi yang tahu bagaimana melakukan ini?
sumber
for
loop!Jawaban:
Seperti yang disinggung oleh beberapa komentator, SQL adalah pilihan yang baik untuk mengekspresikan set kendala yang agak rumit. The sqldf paket memudahkan untuk menggunakan kekuatan SQL di R tanpa perlu untuk membuat sebuah database relasional sendiri.
Inilah solusi menggunakan SQL. Sebelum menjalankan, saya harus mengganti nama kolom interval data Anda ke
startTime
danendTime
karena namanyafrom
dicadangkan dalam SQL.Untuk membantu pemahaman, respons SQL
dupes_wide
akhirnya tampak seperti ini:Bergabung sendiri
FROM testdata x JOIN testdata y
: Menemukan pasangan baris dari satu dataset adalah bergabung sendiri. Kita perlu membandingkan setiap baris dengan yang lainnya. TheON
ekspresi daftar kendala untuk menjaga pasangan.Interval yang tumpang tindih : Saya cukup yakin definisi tumpang tindih yang saya gunakan dalam SQL ( sumber ) ini berbeda dari apa
foverlaps
yang dilakukan untuk Anda. Anda menggunakan tipe "dalam", yang mengharuskan pengamatan di awalobsPoint
sepenuhnya di dalam pengamatan di kemudian hariobsPoint
(tetapi ia melewatkan yang sebaliknya, misalnya jika pengamatan C sepenuhnya berada dalam B ). Untungnya mudah dalam SQL jika Anda perlu menyandikan definisi tumpang tindih yang berbeda.Poin berbeda : Batasan Anda bahwa duplikat dibuat dari titik observasi berbeda akan benar-benar diungkapkan
(x.obsPoint <> y.obsPoint)
. Jika saya mengetiknya, SQL akan mengembalikan setiap pasangan duplikat dua kali, hanya dengan urutan pengalihan burung di setiap baris. Alih-alih, saya menggunakan a<
untuk menjaga hanya setengah baris yang unik. (Ini bukan satu-satunya cara untuk melakukan ini)ID duplikat unik : Seperti halnya solusi Anda sebelumnya, SQL sendiri mencantumkan duplikat di baris yang sama.
hex(randomblob(16))
adalah cara hacky ( belum disarankan ) dalam SQLite untuk menghasilkan ID unik untuk setiap pasangan.Format output : Anda tidak menyukai duplikat di baris yang sama, jadi
melt
pisahkan, danmerge
berikan duplikat ID kembali ke kerangka data awal Anda.Keterbatasan : Solusi saya tidak menangani kasing di mana burung yang sama ditangkap di lebih dari dua trek . Ini lebih rumit dan agak tidak jelas. Misalnya, jika rentang waktunya terlihat seperti
maka Bird1 adalah duplikat Bird2 , yang merupakan duplikat Bird3 , tetapi apakah Bird1 dan Bird3 duplikat?
sumber