2011-12-09 5 views
7

एक टेक्स्ट फ़ाइल में कैसे पढ़ा जा सकता है जिसमें प्रत्येक रिकॉर्ड एक अनुच्छेद है और प्रत्येक नई पंक्ति अलग फ़ील्ड को दर्शाती है। जटिलता यह है कि कुछ रिकॉर्डों में 4 लाइनें होती हैं और कुछ में 6 होती हैं। @ डीडब्ल्यून ने मेरे प्रश्नों को खारिज कर दिया जब फ़ील्ड की संख्या में अंतर 1 था, लेकिन यह दो अलग होने पर अलग हो गया। आपके पास look at his answer here हो सकता है।जब प्रत्येक रिकॉर्ड एक अनुच्छेद होता है और कुछ रिकॉर्ड में 4 फ़ील्ड होते हैं और अन्य के पास 6

तो यहाँ मेरा प्रारंभ पाठ

TheInstitute 5467 
    telephone line 4125526987 x 4567 
    datetime 2011110516 12:56 
    blay blay blah who knows what, but anyway it may have a comma 

TheInstitute 5467 
    telephone line 4125526987 x 4567 
    datetime 2011110516 12:58 
    blay blay blah who knows what 

TheInstitute 5467 
    telephone line 412552999 x 4999 
    bump phone line 4125527777 
    bump pony pony oops 4125527777 
    datetime 2011110516 12:59 
    blay blay blah who knows what 

TheInstitute 5467 
    telephone line 4125526987 x 4567 
    bump phone line 4125527777 
    bump pony pony oops 4125527777 
    datetime 2011110516 13:51 
    blay blay blah who knows what, but anyway it may have a comma 

TheInstitute 5467 
    telephone line 4125526987 x 4567 
    datetime 2011110516 14:56 
    blay blay blah who knows what 

यहाँ उत्पादन की तरह दिखना चाहिए है के नवीनतम अनुकरण है। असल में यह एक कदम है जो मुझे चाहिए। मैं नीचे एक आर डेटा.फ्रेम का ASCII पाठ प्रस्तुतिकरण रख रहा हूं। आप देखेंगे कि सबकुछ डेटा फ्रेम में है लेकिन फ़ील्ड मान दो स्तंभों द्वारा स्थानांतरित किए जाते हैं क्योंकि कुछ रिकॉर्ड में दो अतिरिक्त फ़ील्ड होते हैं।

structure(list(institution = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "TheInstitute 5467", class = "factor"), 
    telephoneline = structure(c(1L, 1L, 2L, 1L, 1L), .Label = c("telephone line 4125526987 x 4567", 
    "telephone line 412552999 x 4999"), class = "factor"), date.or.bump = structure(c(2L, 
    3L, 1L, 1L, 4L), .Label = c("bump phone line 4125527777", 
    "datetime 2011110516 12:56", "datetime 2011110516 12:58", 
    "datetime 2011110516 14:56"), class = "factor"), field4 = structure(c(2L, 
    1L, 3L, 3L, 1L), .Label = c("blay blay blah who knows what", 
    "blay blay blah who knows what, but anyway it may have a comma", 
    "bump pony pony oops 4125527777"), class = "factor"), field5 = structure(c(1L, 
    1L, 2L, 3L, 1L), .Label = c("", "datetime 2011110516 12:59", 
    "datetime 2011110516 13:51"), class = "factor"), field6 = structure(c(1L, 
    1L, 2L, 3L, 1L), .Label = c("", "blay blay blah who knows what", 
    "blay blay blah who knows what, but anyway it may have a comma" 
    ), class = "factor")), .Names = c("institution", "telephoneline", 
"date.or.bump", "field4", "field5", "field6"), class = "data.frame", row.names = c(NA, 
-5L)) 

पुनश्च: हूँ मुझे विश्वास है को सही है कि एक पोस्ट dput का उपयोग कर या एक एक .Rdata सीधे कोई फ़ाइल को यहां बचा सकता है द्वारा एक डेटा फ्रेम।

उत्तर

9

शायद एक और अधिक सुरुचिपूर्ण तरीका है, लेकिन यह काम पूरा करना चाहिए।

x <- readLines("foo.txt") # read data with readLines 
nx <- !nchar(x)   # locate lines with only empty strings 
# create a list (split by empty lines, with empty lines removed) 
y <- split(x[!nx], cumsum(nx)[!nx]) 
# determine largest number of columns 
maxLength <- max(sapply(y,length)) 
# pad each list element with empty strings 
z <- lapply(y, function(x) c(x,rep("",maxLength-length(x)))) 
# create final matrix 
out <- do.call(rbind, z) 

अद्यतन:

यहाँ एक और समाधान plyr::rbind.fill उपयोग कर रहा है:

x <- readLines("foo.txt") # read data with readLines 
nx <- !nchar(x)   # locate lines with only empty strings 
# create final data.frame 
out <- rbind.fill(lapply(split(x[!nx], cumsum(nx)[!nx]), 
        function(x) data.frame(t(x)))) 
5

एक और रणनीति अपने द्वारा चयनित किसी स्ट्रिंग का उपयोग करना है - यह फोन EOL - प्रत्येक पंक्ति के अंत चिह्नित करने के लिए , और उसके बाद सभी लाइनों को एक साथ पेस्ट करें।

फिर आप पहले रिकॉर्ड तोड़ बाहर करने के लिए strsplit के दो दौर का उपयोग कर सकते हैं, और तो रिकॉर्ड के भीतर क्षेत्रों बाहर तोड़। (रिकॉर्ड्स को लगातार दो EOL एस से अलग किया जाएगा, जबकि फ़ील्ड को एक EOL द्वारा अलग किया जाएगा)।

EOL <- "[email protected]" # (for instance) 
x <- readLines("filename.R") 
x <- paste(x, collapse=EOL)[[1]] 

x <- strsplit(x, paste(EOL, EOL, sep=""))   # Split apart records 
lapply(x, FUN=function(X) strsplit(X, EOL))[[1]] # Split apart fields w/in records 

इस विधि मेरे लिए अपील की है क्योंकि यह करने के लिए मैं क्या चाहते हैं, उसके करीब है जब मैं पहली जगह में फ़ाइल में पढ़ा (यानी sep चरित्र के रूप में उपयोग "\n\n"), लेकिन नहीं पा रहा हूँ scan या readLines के साथ करें।

2

पढ़ें डेटा में Dat < -। ReadLines ("filename.txt")

रिकॉर्ड (जोश ओ ब्रायन समाधान से प्रेरित) द्वारा विभाजित डेटा

dat_rec <- lapply(strsplit(paste(dat,collapse="\n"),split="\n\n")[[1]], 
        function(x) strsplit(x,split="\n")[[1]]) 

नामित वैक्टर करने के लिए डेटा रूपांतरण (मान लें कि अंतिम क्षेत्र टिप्पणी है और डेटा संख्यात्मक मान के साथ शुरू होता है)

dat_rec_vn <- lapply(dat_rec,function(x) { 
          vn <- gsub(" ","_",sub(" ","", 
             gsub("^(\\D*) \\d.*$","\\1", x[-length(x)]))) 
          y <- gsub("^(\\D*) (\\d.*)$","\\2",x[-length(x)]) 
          names(y) <- vn 
          return(y)}) 

डेटा में फ़ील्ड के अद्वितीय नाम प्राप्त करें।

vn <- unique(unlist(lapply(dat_rec_vn,names),use.names=FALSE)) 

क्षेत्र को मैट्रिक्स में मिलाएं और इसे नाम दें।

dat_mat <- do.call(rbind,lapply(dat_rec_vn,function(x) { 
        y <- vector(mode="character",length=length(vn)) 
        y[match(names(x),vn)] <- x 
        return(y)})) 

colnames(dat_mat) <- vn 

दूसरा समाधान (gawk का उपयोग कर)

gawk_cmd <- "gawk 'BEGIN{FS=\"\\n\";RS=\"\";OFS=\"\\t\";ORS=\"\\n\"} 
         {$1=$1; print $0}' test_multi.txt" 
dat <- strsplit(system(gawk_cmd,intern=TRUE),split="\t") 
NF <- do.call(max,lapply(dat,length)) 
M <- do.call(rbind,lapply(dat,"[",seq(NF))) 
+0

आप कृपया समझा सकते हैं कि '[[1]]' पहली पंक्ति में कर रहा है? – Farrel

+0

strsplit चरित्र वेक्टर के प्रत्येक तत्व के लिए वैक्टरों की सूची लौटाता है (यहां तक ​​कि लंबाई के चरित्र वेक्टर के लिए भी)। हमें इस सूची में पहले तत्व की आवश्यकता है ताकि [[1]] इसे प्राप्त करने के लिए उपयोग किया जा सके। दूसरी पंक्ति पर एक ही फ़ंक्शन का उपयोग किया जाता है। –

+0

ओह, तो क्या यह एक सूची को सदिश बनाने का एक तरीका होगा जब तक कि केवल एक ही तत्व चाहता था? – Farrel

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