2013-02-19 62 views
5

मैं नियमित अंतराल पर एक स्ट्रिंग को विभाजित करना चाहता हूं। मेरा प्रश्न इस तरह के समान है: How to split a string into substrings of a given length? सिवाय इसके कि मेरे पास केवल एक स्ट्रिंग के बजाय डेटा सेट में तारों का एक स्तंभ है।नियमित अंतराल पर विभाजित स्ट्रिंग

df = read.table(text = " 
my.id X1  
010101 1 
010102 1 
010103 1 
010104 1 
020101 1 
020112 1 
021701 0 
021802 0 
133301 0 
133302 0 
241114 0 
241215 0 
", header = TRUE, colClasses=c('character', 'numeric'), stringsAsFactors = FALSE) 

यहाँ वांछित परिणाम है:

यहाँ एक उदाहरण डेटा सेट है। मैं दिखाया गया है, अग्रणी शून्य को दूर करना पसंद करेंगे:

desired.result = read.table(text = " 
A1 A2 A3 X1 
1 1 1 1 
1 1 2 1 
1 1 3 1 
1 1 4 1 
2 1 1 1 
2 1 12 1 
2 17 1 0 
2 18 2 0 
13 33 1 0 
13 33 2 0 
24 11 14 0 
24 12 15 0 
", header = TRUE, colClasses=c('numeric', 'numeric', 'numeric', 'numeric'), stringsAsFactors = FALSE) 

यहाँ एक पाश है कि करीब आ रहा है और हो सकता है कि मैं इसे का उपयोग कर सकते है। हालांकि, मैं सोच रहा हूं कि एक और अधिक प्रभावी तरीका है।

for(i in 1:nrow(df)) { 
    print(substring(df$my.id[i], seq(1, 5, 2), seq(2, 6, 2))) 
} 

यह apply बयान काम नहीं करता:

apply(df$my.id, 1, function(x) substring(df$my.id[x], seq(1, 5, 2), seq(2, 6, 2)) ) 

किसी भी सुझाव के लिए धन्यवाद। मैं आधार आर

उत्तर

10

str_extract_all साथ संयोजन के रूप में इस का उपयोग किया है मुझे लगता है कि read.fwf एक textConnection के लिए लागू सबसे अधिक कुशल और आसानी से समझ में विभिन्न तरीकों से एक इस दृष्टिकोण सकता है। इसका स्वचालित वर्ग पहचान का लाभ है जिसे पढ़ने में बनाया गया है। * फ़ंक्शंस।

cbind(read.fwf(file=textConnection(df$my.id), 
       widths=c(2,2,2), col.names=paste0("A", 1:3)), 
    X1=df$X1) 
#----------- 
    A1 A2 A3 X1 
1 1 1 1 1 
2 1 1 2 1 
3 1 1 3 1 
4 1 1 4 1 
5 2 1 1 1 
6 2 1 12 1 
7 2 17 1 0 
8 2 18 2 0 
9 13 33 1 0 
10 13 33 2 0 
11 24 11 14 0 
12 24 12 15 0 

(मुझे विश्वास है कि मैंने इसे लगभग 6 साल पहले रेलप पर गैबर ग्रोथेंडिक से सीखा था।)

यदि आप रेगेक्स रणनीति पसंद करते हैं तो इसे देखें जो प्रत्येक दो पदों पर एक टैब डालता है और इसे read.table के माध्यम से चलाता है। बहुत कॉम्पैक्ट:

read.table(text=gsub('(.{2})','\\1\t',df$my.id)) 
#--------- 
    V1 V2 V3 
1 1 1 1 
2 1 1 2 
3 1 1 3 
4 1 1 4 
5 2 1 1 
6 2 1 12 
7 2 17 1 
8 2 18 2 
9 13 33 1 
10 13 33 2 
11 24 11 14 
12 24 12 15 
3

में एक समाधान पसंद करता हूं आप लगभग वहां हैं। बदलें अपनी applysapply या vapply, और बदल क्या पर substring कार्यों के लिए:

splt <- sapply(df$my.id, function(x) substring(x, seq(1, 5, 2), seq(2, 6, 2)) ) 
#this will produce the same thing 
splt <- vapply(df$my.id, function(x) substring(x, seq(1, 5, 2), seq(2, 6, 2)),c("","","") ) 
#  010101 010102 010103 010104 020101 020112 021701 021802 133301 133302 241114 241215 
#[1,] "01" "01" "01" "01" "02" "02" "02" "02" "13" "13" "24" "24" 
#[2,] "01" "01" "01" "01" "01" "01" "17" "18" "33" "33" "11" "12" 
#[3,] "01" "02" "03" "04" "01" "12" "01" "02" "01" "02" "14" "15" 

आप इन संख्यात्मक बनाना चाहते थे। डेटा फ्रेम के साथ काम करने के लिए मैट्रिक्स को भी स्थानांतरित किया जाना चाहिए। हम दोनों चरणों के साथ कर सकते हैं:

splt <- apply(splt,1,as.numeric) 
    # [,1] [,2] [,3] 
# [1,] 1 1 1 
# [2,] 1 1 2 
# [3,] 1 1 3 
# [4,] 1 1 4 
# [5,] 2 1 1 
# [6,] 2 1 12 
# [7,] 2 17 1 
# [8,] 2 18 2 
# [9,] 13 33 1 
# [10,] 13 33 2 
# [11,] 24 11 14 
# [12,] 24 12 15 

अब आपको इसे अपने पुराने डेटा फ्रेम के साथ एक साथ रखना होगा। संभवतः निम्नलिखित की तरह कुछ।

df <- cbind(splt,df) 
# 1 2 3 my.id X1 
#1 1 1 1 010101 1 
#2 1 1 2 010102 1 
#3 1 1 3 010103 1 
#4 1 1 4 010104 1 
#5 2 1 1 020101 1 
#6 2 1 12 020112 1 
#7 2 17 1 021701 0 
#8 2 18 2 021802 0 
#9 13 33 1 133301 0 
#10 13 33 2 133302 0 
#11 24 11 14 241114 0 
#12 24 12 15 241215 0 

आप names(df)[1:3] <- c("A1","A2","A3") की तरह कुछ के साथ आवश्यक के रूप में स्तंभ नाम बदल सकते हैं।

2

gsub और कुछ नियमित अभिव्यक्ति का उपयोग करना। मैं कुछ इस तरह करना होगा (बहुत ही सुंदर नहीं है, लेकिन यह काम करते हैं)

cbind(
as.numeric(gsub('([0-9]{2})([0-9]{2})([0-9]{2})','\\1',df$my.id)), 
as.numeric(gsub('([0-9]{2})([0-9]{2})([0-9]{2})','\\2',df$my.id)), 
as.numeric(gsub('([0-9]{2})([0-9]{2})([0-9]{2})','\\3',df$my.id)), 
df$X1) 

    [,1] [,2] [,3] [,4] 
[1,] 1 1 1 1 
[2,] 1 1 2 1 
[3,] 1 1 3 1 
[4,] 1 1 4 1 
[5,] 2 1 1 1 
[6,] 2 1 12 1 
[7,] 2 17 1 0 
[8,] 2 18 2 0 
[9,] 13 33 1 0 
[10,] 13 33 2 0 
[11,] 24 11 14 0 
[12,] 24 12 15 0 

संपादित

मैं ने कहा कि यह बहुत ही सुंदर नहीं है, इसलिए मैं @mnel प्रस्ताव जोड़ें:

x <- gsub('([0-9]{2})([0-9]{2})([0-9]{2})','\\1-\\2-\\3',df$my.id) 
do.call(rbind, lapply(strsplit(x,'-'), as.numeric)) 
+2

मेरा सुझाव था शायद 'x <- gsub ('([0-9] {2}) ([0-9] {2}) ([0-9] {2}) ',' \\ 1 - \\ 2 - \\ 3 ', df $ my.id); do.call (rbind, lapply (strsplit (x, '-), as.numeric))' लिखने और 'regex' को कई बार करने से बचने के लिए। – mnel

+0

बहुत अच्छा! मैंने एक कीस्ट्रोक जोड़ा: strsplit (x, '-') –

+0

@mnel धन्यवाद। मैं अपना जवाब अपडेट करता हूं। – agstudy

2

आप प्रत्येक दो-अंकों वाले खंड को निकालने के लिए regex का भी उपयोग कर सकते हैं।

मैं से stringr

do.call(rbind,lapply(str_extract_all(as.character(df[['my.id']]), pattern = '[[:digit:]]{2}'), as.numeric)) 
+0

यदि आप आधार समाधान चाहते हैं, तो आप 'str_extract_all' को' regmatches (gregexpr (पैटर्न, x)) के साथ प्रतिस्थापित करने में सक्षम हो सकते हैं। –

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