2016-08-19 9 views
6

मैं डेटा फ्रेम की पंक्तियों को जोड़ना चाहता हूं जैसे "प्रारंभ" और "अंत" कॉलम द्वारा वर्णित श्रेणियों में मूल डेटा सेट के सभी मान शामिल हैं। ओवरलैप, दोहराने और घोंसला वाली श्रेणियां हो सकती हैं। कुछ श्रेणियां गायब हो सकती हैं।दिनांक सीमाओं के आधार पर पंक्तियों को समेकित करें

यहाँ जिस प्रकार का डेटा का एक उदाहरण मैं संक्षिप्त करने के लिए करना चाहते हैं क्या है:

data = data.frame(rbind(
    c("Roger", 1, 10), 
    c("Roger", 10, 15), 
    c("Roger", 16, 17), 
    c("Roger", 3, 6), 
    c("Roger", 20, 25), 
    c("Roger", NA, NA), 
    c("Susan", 2, 8))) 
names(data) = c("name", "start", "end") 
data$start = as.numeric(as.character(data$start)) 
data$end = as.numeric(as.character(data$end)) 

वांछित परिणाम होगा:

name start end 
Roger 1  17 
Roger 20 25 
Susan 2  8 

मेरे प्रयास में हर आइटम बाहर का विस्तार करने में किया गया है प्रत्येक पंक्ति के लिए सीमा। यह काम करता है, लेकिन फिर मुझे यकीन नहीं है कि इसे वापस कैसे कम करें। इसके अतिरिक्त, जिन पूर्ण डेटासेट के साथ मैं काम कर रहा हूं उनमें ~ 30 मिलियन पंक्तियां और बहुत बड़ी श्रेणियां हैं, इसलिए यह विधि बहुत धीमी है।

pb <- txtProgressBar(min = 0, max = length(data$name), style = 3) 
mylist = list() 
for(i in 1:length(data$name)){ 
    subdata = data[i,] 
    if(is.na(subdata$start)){ 
    mylist[[i]] = subdata 
    mylist[[i]]$each = NA 
    } 
    if(!is.na(subdata$start)){ 
    sequence = seq(subdata$start, subdata$end) 
    mylist[[i]] = subdata[rep(1, each = length(sequence)),] 
    mylist[[i]]$daily = sequence 
    } 
    setTxtProgressBar(pb, i) 
} 

rbindlist(mylist) 
+0

शायद यह स्पष्ट है लेकिन रोजर दो बार क्यों दिख रहा है? और शुरुआत = 1 और अंत = 25 के साथ एक पंक्ति में नहीं? – snoram

+0

@snoram अच्छा सवाल। क्योंकि रोजर के पास 18 या 1 9 नहीं था, इसलिए दो रिकॉर्ड उनकी श्रेणियों में अंतर को दर्शाते हैं। – Nancy

+2

संबंधित: [आर में क्षेत्रों को छेड़छाड़ करना] (http://stackoverflow.com/questions/16957293/collapse-intersecting-regions-in-r) और [अद्वितीय समूहों में ओवरलैपिंग रेंज मर्ज करें] (http://stackoverflow.com/प्रश्न/15235821/विलय-ओवरलैपिंग-श्रेणी-में-अद्वितीय-समूह) – Henrik

उत्तर

10

मैं IRanges अनुमान लगा रहा हूँ बहुत अधिक इस के लिए कुशल, लेकिन ...

library(data.table) 

# remove missing values 
DT = na.omit(setDT(data)) 

# sort 
setorder(DT, name, start) 

# mark threshold for a new group 
DT[, high_so_far := shift(cummax(end), fill=end[1L]), by=name] 

# group and summarise 
DT[, .(start[1L], end[.N]), by=.(name, g = cumsum(start > high_so_far + 1L))] 

#  name g V1 V2 
# 1: Roger 0 1 17 
# 2: Roger 1 20 25 
# 3: Susan 1 2 8 

यह कैसे काम करता:

  • cummax संचयी अधिकतम है, इसलिए वर्तमान पंक्ति सहित अब तक का उच्चतम मूल्य।
  • वर्तमान पंक्ति को छोड़कर मूल्य को लेने के लिए, shift (जो पूर्व पंक्ति से खींचता है) का उपयोग करें।
  • cumsum(some_condition) समूहबद्ध चर बनाने का एक मानक तरीका है।
  • .Nby= द्वारा निर्धारित समूह की अंतिम पंक्ति है।

कॉलम को .(s = start[1L], e = end[.N]) जैसे अंतिम चरण में नामित किया जा सकता है।


तारीख अंतराल साथ । यदि तिथियों के साथ काम करना है, तो मैं IDate कक्षा का सुझाव दूंगा; Date को परिवर्तित करने के लिए बस as.IDate का उपयोग करें।

हम कर सकते हैं +1 तारीखों को, लेकिन दुर्भाग्य से नहीं cummax कर सकते हैं, तो ...

cummax_idate = function(x) (setattr(cummax(unclass(x)), "class", c("Date", "IDate"))) 

set.seed(1) 
d = sample(as.IDate("2011-11-11") + 1:10) 
cummax_idate(d) 
# [1] "2011-11-14" "2011-11-15" "2011-11-16" "2011-11-18" "2011-11-18" 
# [6] "2011-11-19" "2011-11-20" "2011-11-20" "2011-11-21" "2011-11-21" 

मैं इस समारोह cummax के स्थान पर इस्तेमाल किया जा सकता है।

फ़ंक्शन में अतिरिक्त () हैं क्योंकि setattr इसके आउटपुट को प्रिंट नहीं करेगा।

+0

मैं 'na.omit' को' set.Tit' के बाद लागू किया जाएगा ताकि अंततः तेज़ 'na.omit.data.table' विधि का उपयोग किया जा सके। – jangorecki

+0

ठीक है, किया।धन्यवाद, @jangorecki – Frank

+0

@ यह बहुत अच्छा है। मैं वास्तव में तिथि सीमाओं के लिए इस का उपयोग कर रहा है, लेकिन तारीखों के संख्यात्मक करने के लिए तिथि और फिर रूपांतरण से वापस इस विधि के साथ काम करता है और तारीखों को बरकरार रखता है। – Nancy

संबंधित मुद्दे