2013-02-25 48 views
11

में संख्यात्मक अनुक्रम मैं नीचे के समान संख्या का एक अनुक्रम के साथ एक dataframe है:खोज और बदल आर

data <- c(1,1,1,0,0,1,1,2,2,2,0,0,0,2,1,1,0,1,0,2) 

क्या मैं जरूरत 0 जहां की 1, 2 या 3 repetitions के सभी मामले ढूंढने के लिए कुछ है कार्यवाही और निम्नलिखित संख्याएं समान हैं- यानी दोनों 1 या दोनों 2 (उदाहरण के लिए 1,0,1 या 2,0,0,2 लेकिन 2,0,1 नहीं)।

फिर मुझे केवल आसपास के मूल्य के साथ शून्य को भरने की आवश्यकता है।

मैं पता लगाने और बाद एक कई शून्य

गिनती में कामयाब रहे
consec <- (!data) * unlist(lapply(rle(data)$lengths, seq_len)) 

तो मैं पंक्ति जहां इन बाद एक कई शून्य के साथ शुरू पाया है:

consec <- as.matrix(consec) 
first_na <- which(consec==1,arr.ind=TRUE) 

लेकिन मैं प्रतिस्थापन प्रक्रिया

साथ स्टम्प्ड हूँ

मैं वास्तव में आपकी सहायता की सराहना करता हूं!

कार्ल

उत्तर

2

चूंकि इस प्रश्न के उत्तर में बहुत रुचि दिखाई देती है, मैंने सोचा कि मैं वंशावली के लिए एक वैकल्पिक नियमित अभिव्यक्ति विधि लिखूंगा।

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

नोट: निम्न उदाहरण लिखित के रूप में काम करता है, क्योंकि हम एकल-अंक मान मान रहे हैं। हम इसे अन्य पैटर्न के लिए आसानी से अनुकूलित कर सकते हैं, लेकिन हम एकल पात्रों के साथ एक छोटा सा शॉर्टकट ले सकते हैं। यदि हम संभावित बहु-अंकों के मूल्यों के साथ ऐसा करना चाहते हैं, तो हम पहले संयोजन ('पेस्ट') फ़ंक्शन के हिस्से के रूप में एक अलगाव चरित्र जोड़ना चाहते हैं।


कोड

str.values <- paste(data, collapse="") # String representation of vector 
str.matches <- gregexpr("1[0]{1,3}1", str.values) # Pattern 101/1001/10001 
data[eval(parse(text=paste("c(",paste(str.matches[[1]] + 1, str.matches[[1]] - 2 + attr(str.matches[[1]], "match.length"), sep=":", collapse=","), ")")))] <- 1 # Replace zeros with ones 
str.matches <- gregexpr("2[0]{1,3}2", str.values) # Pattern 202/2002/20002 
data[eval(parse(text=paste("c(",paste(str.matches[[1]] + 1, str.matches[[1]] - 2 + attr(str.matches[[1]], "match.length"), sep=":", collapse=","), ")")))] <- 2 # Replace zeros with twos 

चरण 1: सभी डेटा मानों की एक एकल स्ट्रिंग बनाओ।

str.values <- paste(data, collapse="") 
# "11100112220002110102" 

यह डेटा को एक लंबी स्ट्रिंग में ढहता है, इसलिए हम उस पर एक नियमित अभिव्यक्ति का उपयोग कर सकते हैं।

चरण 2: स्ट्रिंग के भीतर किसी भी मैचों के स्थानों और लंबाई को खोजने के लिए नियमित अभिव्यक्ति लागू करें।

str.matches <- gregexpr("1[0]{1,3}1", str.values) 
# [[1]] 
# [1] 3 16 
# attr(,"match.length") 
# [1] 4 3 
# attr(,"useBytes") 
# [1] TRUE 

इस मामले में, हम एक नियमित अभिव्यक्ति का उपयोग कर रहे लोगों के साथ एक से तीन शून्य ([0]{2,}) दोनों ओर (1[0]{1,3}1) पर पहला पैटर्न देखने के लिए। अंतराल पर मिलान करने वाले लोगों या जुड़वाओं की जांच करने से रोकने के लिए हमें पूरे पैटर्न से मेल खाना पड़ेगा। हम अगले चरण में उन छोरों को घटा देंगे।

चरण 3: मूल वेक्टर में सभी मिलान स्थानों में लिखें।

data[eval(parse(text=paste("c(",paste(str.matches[[1]] + 1, str.matches[[1]] - 2 + attr(str.matches[[1]], "match.length"), sep=":", collapse=","), ")")))] <- 1 
# 1 1 1 1 1 1 1 2 2 2 0 0 0 2 1 1 1 1 0 2 

हम यहां एक ही समय में कुछ कदम उठा रहे हैं। सबसे पहले, हम नियमित अभिव्यक्ति में मेल खाने वाली संख्याओं से संख्या अनुक्रमों की एक सूची बना रहे हैं। इस मामले में, दो मैच हैं, जो इंडेक्स 3 और 16 से शुरू होते हैं और क्रमशः 4 और 3 आइटम लंबे होते हैं। इसका मतलब है कि हमारे शून्य इंडेक्स (3 + 1) :(3-2 + 4), या 4: 5 और (16 + 1) :(16-2 + 3), या 17:17 पर स्थित हैं। कई मैचों के मामले में, हम 'पतन' विकल्प का उपयोग करके इन अनुक्रमों को दोबारा जोड़ते हैं ('पेस्ट')। फिर, हम अनुक्रमों को एक गठबंधन (c()) फ़ंक्शन के अंदर रखने के लिए एक दूसरा संयोजन का उपयोग करते हैं। 'Eval' और 'parse' फ़ंक्शंस का उपयोग करके, हम इस पाठ को कोड में बदल देते हैं और इसे [डेटा] सरणी में इंडेक्स मान के रूप में पास करते हैं। हम सभी को उन स्थानों में लिखते हैं।

चरण x: प्रत्येक पैटर्न के लिए दोहराना। इस मामले में, हमें दूसरी खोज करने की आवश्यकता है और दोनों तरफ जुड़वा के साथ एक से तीन शून्य खोजें और फिर चरण 3 के समान कथन चलाएं, लेकिन किसी के बजाय जुड़वां असाइन करें।

str.matches <- gregexpr("2[0]{1,3}2", str.values) 
# [[1]] 
# [1] 10 
# attr(,"match.length") 
# [1] 5 
# attr(,"useBytes") 
# [1] TRUE 

data[eval(parse(text=paste("c(",paste(str.matches[[1]] + 1, str.matches[[1]] - 2 + attr(str.matches[[1]], "match.length"), sep=":", collapse=","), ")")))] <- 2 
# 1 1 1 1 1 1 1 2 2 2 2 2 2 2 1 1 1 1 0 2 

अद्यतन: मुझे एहसास हुआ कि मूल समस्या के बजाय "दो या अधिक" है कि मैं मूल कोड में लिखा, एक पंक्ति में एक से तीन शून्य से मेल करने के लिए कहा। मैंने नियमित अभिव्यक्तियों और स्पष्टीकरण को अद्यतन किया है, हालांकि कोड वही रहता है।

+0

इसलिए, मैं वास्तव में अंत में इस के लिए गया, मुझे पैटर्न पर नियंत्रण रखने की क्षमता पसंद थी - लेकिन मैंने सभी सुझावों की सराहना की। हालांकि मैं अलग-अलग परिस्थितियों के लिए इन विभिन्न विधियों पर ध्यान रखूंगा। मैं इसकी प्रशंसा करता हूँ। –

1

वहाँ एक for पाश के बिना एक समाधान हो सकता है, लेकिन आप यह कोशिश कर सकते हैं:

tmp <- rle(data) 
val <- tmp$values 
for (i in 2:(length(val)-1)) { 
    if (val[i]==0 & val[i-1]==val[i+1]) val[i] <- val[i-1] 
} 
tmp$values <- val 
inverse.rle(tmp) 

कौन देता है:

[1] 1 1 1 1 1 1 1 2 2 2 2 2 2 2 1 1 1 1 0 2 
+0

मुझे लगता है कि आप 'rle (as.logical (डेटा)) कर कर इसे "कस लें" कर सकते हैं जो आपके' tmp' को 'शून्य' और 'शून्य-शून्य' की लंबाई के साथ भर देगा, जिसके बाद आप प्रतिस्थापित कर सकते हैं शून्य के प्रत्येक भाग 'वैल [i-1] * (वैल [i-1] == वैल [i + 1]) के साथ शून्य। (यदि मैंने इसे खराब कर दिया है, तो इरादे को 'वैल [i-1]' के साथ शून्यों को प्रतिस्थापित करना है, लेकिन केवल तभी जब समानता जांच सत्य है) - 'यह' बल्कि सावधानी से होना चाहिए :-(un-rle -ed –

+0

@CarlWitthoft हम्म यदि आप 'rle (as.logical (डेटा)) का उपयोग करते हैं, तो आप मूल्यों की समानता के परीक्षण के लिए अपने' Rle $ values' का उपयोग नहीं कर सकते हैं? – juba

+0

नेवावाइंड - एंड्री का जवाब मैं करता हूं और भी कॉम्पैक्टली (और भरोसेमंद) के बारे में सोच रहा था। –

14

यहाँ rle() का उपयोग कर एक loopless समाधान है और inverse.rle()

data <- c(1,1,1,0,0,1,1,2,2,2,0,0,0,2,1,1,0,1,0,2) 

local({ 
    r <- rle(data) 
    x <- r$values 
    x0 <- which(x==0) # index positions of zeroes 
    xt <- x[x0-1]==x[x0+1] # zeroes surrounded by same value 
    r$values[x0[xt]] <- x[x0[xt]-1] # substitute with surrounding value 
    inverse.rle(r) 
}) 

[1] 1 1 1 1 1 1 1 2 2 2 2 2 2 2 1 1 1 1 0 2 

पी एस। मैं local() का उपयोग एक सरल तंत्र के रूप में करता हूं ताकि वर्कस्पेस को नए अस्थायी वस्तुओं के भार से ढंकने के लिए नहीं किया जा सके। local का उपयोग करने के बजाय आप function बना सकते हैं - मुझे लगता है कि मैं इस प्रकार के कार्य के लिए आजकल local का उपयोग करता हूं।


पीपीएस। आपको अपने मूल डेटा में अग्रणी या पीछे वाले शून्य को बाहर करने के लिए इस कोड को संशोधित करना होगा।

+0

यह 'राल' फ़ंक्शन का उपयोग करने का बिल्कुल सही तरीका है, और मुझे खुशी है कि आपने इसे स्पष्ट रूप से लिखा है। 'स्थानीय' फ़ंक्शन भी एक अच्छी टिप है। मैं अपने कोड को बहुत सारे कार्यों में लपेटकर लगभग एक ही काम करता हूं (डीबगिंग के लिए भी अच्छा), और मुझे लगता है कि लोगों के लिए सामान्य रूप से सीखना एक अच्छी बात है। अच्छा काम, एंड्री। – Dinre