आर में दो और मानदंडों के साथ अतिव्यापी समय अंतराल की पहचान करना?


10

मुझे डुप्लिकेट / ओवरलैपिंग प्रविष्टियों के लिए लंबी अवधि में किए गए पक्षियों के अवलोकन की जांच करनी होगी।

विभिन्न बिंदुओं (ए, बी, सी) के पर्यवेक्षकों ने अवलोकन किए और उन्हें कागज़ के नक्शे पर चिह्नित किया। उन पंक्तियों को जहां प्रजातियों के लिए अतिरिक्त डेटा के साथ एक पंक्ति सुविधा में लाया गया था, अवलोकन बिंदु और समय अंतराल जो उन्हें देखा गया था।

आम तौर पर, पर्यवेक्षक अवलोकन के दौरान फोन के माध्यम से एक-दूसरे के साथ संवाद करते हैं, लेकिन कभी-कभी वे भूल जाते हैं, इसलिए मुझे उन डुप्लिकेट लाइनें मिलती हैं।

मैंने उन डेटा को पहले से ही कम कर दिया है जो सर्कल को छूते हैं, इसलिए मुझे एक स्थानिक विश्लेषण करने की आवश्यकता नहीं है, लेकिन केवल प्रत्येक प्रजातियों के लिए समय अंतराल की तुलना करें और यह सुनिश्चित कर सकते हैं कि यह वही व्यक्ति है जो तुलना द्वारा पाया जाता है ।

मैं अब उन प्रविष्टियों की पहचान करने के लिए R में एक रास्ता खोज रहा हूँ जो:

  • एक ही दिन में एक अतिव्यापी अंतराल के साथ बनाया जाता है
  • और जहां यह एक ही प्रजाति है
  • और जो अलग-अलग अवलोकन बिंदुओं (A या B या C या ...) से बनाए गए थे)

यहां छवि विवरण दर्ज करें

इस उदाहरण में, मैंने मैन्युअल रूप से एक ही व्यक्ति की संभवतः नकली प्रविष्टियों को पाया। अवलोकन बिंदु अलग है (ए <-> बी), प्रजाति एक ही (एसटीएस) है और प्रारंभ और अंत के अंतराल ओवरलैप होते हैं।

यहां छवि विवरण दर्ज करें

अब मैं अपने डेटा.फ्रेम में एक नया फ़ील्ड "डुप्लिकेट" बनाऊंगा, जिससे दोनों पंक्तियों को एक आम आईडी दी जा सकेगी जो उन्हें निर्यात करने में सक्षम होगी और बाद में तय करेगी कि क्या करना है।

मैंने पहले से ही उपलब्ध समाधानों के लिए बहुत खोज की, लेकिन इस तथ्य के बारे में कोई भी नहीं पाया कि मुझे प्रजातियों के लिए प्रक्रिया को कम करना है (अधिमानतः बिना लूप के) और 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")

मुझे डेटा के साथ एक आंशिक समाधान मिला। उल्लेखनीय कार्य 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)

बेशक, यह किसी भी तरह "काम करता है", लेकिन वास्तव में वह नहीं है जो मुझे अंत में हासिल करना पसंद है।

पहले, मुझे अवलोकन बिंदुओं को कठिन कोड करना होगा। मैं मनमाने ढंग से अंक लेते हुए समाधान ढूंढना पसंद करूंगा।

दूसरा, परिणाम एक प्रारूप में नहीं है कि मैं वास्तव में आसानी से काम करना फिर से शुरू कर सकता हूं। मिलान पंक्तियों को वास्तव में उसी पंक्ति में रखा जाता है, जबकि मेरा लक्ष्य पंक्तियों को नीचे रखना है, और एक नए कॉलम में, उनके पास एक सामान्य पहचानकर्ता होगा।

तीसरा, मुझे मैन्युअल रूप से फिर से जांचना होगा, अगर तीनों बिंदुओं से अंतराल समाप्त हो जाता है (जो मेरे डेटा के साथ ऐसा नहीं है, लेकिन आम तौर पर हो सकता है)

अंत में, मैं बस एक नया डेटा प्राप्त करना चाहूंगा। समूह आईडी द्वारा पहचाने जाने वाले सभी उम्मीदवारों के साथ कि मैं वापस लाइनों में शामिल हो सकता हूं और आगे की परीक्षा के लिए एक परत के रूप में परिणाम निर्यात कर सकता हूं।

तो किसी को यह कैसे करना है?


मुझे यकीन नहीं है कि मैं पूरी तरह से समझता हूं, लेकिन यह एक कार्य की तरह लगता है जो कि पोस्टग्रेक्यूएल में काफी सीधे आगे है। समय सीमा के लिए कार्य है। जैसा कि मैंने समझा है कि PostgreSQL और R. के बीच डेटा साझा करना आसान होना चाहिए
निकल्स अवेन

मुझे यह स्वीकार करना होगा कि मुझे पोस्टग्रेज का शून्य ज्ञान नहीं है, लेकिन वास्तव में, आज शाम को बीयर पीते समय, मुझे यह भी विचार था कि इसके लिए कुछ sql सामान उपलब्ध हो सकता है। मेरे बाकी कार्यों के लिए मुझे डेटासेट के साथ क्या करना है, आर हालांकि उपकरण है, लेकिन मुझे पता है कि कुछ संकुल के माध्यम से आर के भीतर एसक्यूएल फ़ंक्शन भी किए जा सकते हैं। तहकीकात ....
बेरंड वी।

डेटासेट कितना बड़ा है - सैकड़ों, हजारों, लाखों पंक्तियाँ? SQL फ़ंक्शंस के लिए आपको sqldf मिला ?
सिमबंगु

इस बीच, मुझे एक काम करने वाला समाधान मिला। मुझ पर शर्म करो मैंने इसे अब तक पोस्ट नहीं किया। दूसरों के लिए उपयोग करने के लिए इसे और अधिक सामान्य बनाना होगा, और फिर मैं इसे asap पोस्ट करूंगा।
बेरंड वी।

यह सब सदिश होने पर +1 करेगा और forलूप का उपयोग नहीं करेगा !
सिंबांगु

जवाबों:


1

जैसा कि कुछ टिप्पणीकारों ने कहा, SQL बाधाओं के जटिल सेटों को व्यक्त करने के लिए एक अच्छा विकल्प है। Sqldf पैकेज आसान अपने आप को एक संबंधपरक डेटाबेस स्थापित करने के लिए की जरूरत के बिना आर में एसक्यूएल की शक्ति का उपयोग करने के लिए बनाता है।

यहाँ SQL का उपयोग कर एक समाधान है। दौड़ने से पहले, मुझे आपके डेटा के अंतराल कॉलम को फिर से नाम देना पड़ा startTimeऔर endTimeक्योंकि नाम 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अभिव्यक्ति जोड़े रखने के लिए की कमी सूचीबद्ध करता है।

ओवरलैपिंग अंतराल : मुझे पूरा यकीन है कि इस एसक्यूएल ( स्रोत ) में मैंने जिस ओवरलैप का इस्तेमाल किया है, उसकी परिभाषा foverlapsआपके लिए क्या कर रही थी , उससे अलग है । आपने "भीतर" प्रकार का उपयोग किया है, जिसके लिए पहले अवलोकन करने की आवश्यकता होती है obsPoint, बाद में पूरी तरह से अवलोकन के भीतर obsPoint(लेकिन यह संक्षिप्त याद आती है, जैसे कि C का अवलोकन पूरी तरह से B के s के भीतर है )। सौभाग्य से यह एसक्यूएल में आसान है अगर आपको ओवरलैप की एक अलग परिभाषा को एनकोड करने की आवश्यकता है।

अलग-अलग बिंदु : आपके अवरोध जो कि अलग-अलग अवलोकन बिंदुओं से बनाए गए थे, वास्तव में व्यक्त किए जाएंगे (x.obsPoint <> y.obsPoint)। अगर मैंने टाइप किया होता, तो SQL हर डुप्लिकेट जोड़ी को दो बार लौटा देती, बस पंक्तियों के साथ प्रत्येक पंक्ति में क्रमबद्ध रूप से। इसके बजाय मैंने <केवल पंक्तियों के अनूठे आधे हिस्से को रखने के लिए उपयोग किया । (यह ऐसा करने का एकमात्र तरीका नहीं है)

यूनीक डुप्लिकेट आईडी : अपने पिछले समाधान के साथ, एसक्यूएल स्वयं डुप्लिकेट को उसी पंक्ति में सूचीबद्ध करता है। हर जोड़ी के लिए यूनिक आईडी जनरेट करने के लिए SQLite में hex(randomblob(16))हैकी ( अभी तक अनुशंसित ) तरीका है।

आउटपुट स्वरूप : आप एक ही पंक्ति में डुप्लिकेट को पसंद नहीं करते थे, इसलिए meltउन्हें अलग कर देता है, और mergeडुप्लिकेट आईडी को आपके डेटा डेटा फ्रेम में वापस सौंप देता है।

सीमाएँ : मेरा समाधान उस मामले को नहीं संभालता है जहाँ एक ही पक्षी को दो से अधिक ट्रैकों में पकड़ा जाता है । यह पेचीदा और कुछ हद तक बीमार है। उदाहरण के लिए, यदि उनकी समय सीमा दिखती है

    | - बर्ड 1 - |
             | - बर्ड 2 - |
                      | - बर्ड 3 - |

तो Bird1 का डुप्लिकेट है Bird2 , जिनमें से डुप्लिकेट है Bird3 , लेकिन कर रहे हैं Bird1 और Bird3 डुप्लिकेट?

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.