2012-05-15 6 views
7

मेरे पास एक बड़ी फ़ाइल है जिसमें बहुत सारे डेटा हैं, और मैं इसे डेटाफ्रेम में पढ़ना चाहता हूं, लेकिन कुछ अमान्य पंक्तियां मिलीं। ये अवैध पंक्तियां पढ़ने के लिए read.table का कारण बनती हैं। मैं अमान्य लाइनों को छोड़ने के लिए निम्न विधि का प्रयास करता हूं, लेकिन ऐसा लगता है कि प्रदर्शन बहुत खराब है।आर में फ़ाइल से डेटा फ्रेम पढ़ने के दौरान अवैध पंक्तियों को कैसे छोड़ें?

counts<-count.fields(textConnection(lines),sep="\001") 
raw_data<-read.table(textConnection(lines[counts == 34]), sep="\001") 

क्या यह हासिल करने का कोई बेहतर तरीका है? धन्यवाद

+2

आपकी परिभाषा में क्या बुरा है? –

+1

कोई कारण नहीं है कि आप सीधे 'read.table' का उपयोग नहीं कर रहे हैं? इसमें कई "खराब" वर्णों को चुनने और अनदेखा करने के लिए बहुत सारे तर्क हैं। अपूर्ण पंक्तियों को "भरने" के लिए भी एक तर्क है, यदि यह समस्या है तो आपके पास समस्या है। –

उत्तर

18

का उपयोग कर @ PaulHiemstra के नमूने डेटा:

read.table("test.csv", sep = ";", fill=TRUE) 

तो आप NAS की देखभाल के रूप में आप चाहते हैं ले लो।

+1

मैंने आपके उत्तर को बेंचमार्क –

+0

आलसी के लिए एक अतिरिक्त विकल्प के रूप में जोड़ा - यह मेरी पहली टिप्पणी में मेरा जवाब था, लेकिन आपने इसे अपनी टिप्पणी कर्म के लिए –

+0

@ करल, +1 के बेहतर विवरण में लिखा था। – BenBarnes

5

आप जो कर सकते हैं वह फ़ाइल में लाइनों पर फिर से चलना है, और केवल उन पंक्तियों को जोड़ना जिनमें सही लंबाई है।

मैं निम्नलिखित परीक्षण csv फ़ाइल में परिभाषित किया गया:

1;2;3;4 
1;2;3;4 
1;2;3 
1;2;3;4 

read.table का प्रयोग विफल रहता है:

> read.table("test.csv", sep = ";") 
Error in scan(file, what, nmax, sep, dec, quote, skip, nlines, na.strings, :                  
    line 3 did not have 4 elements 

अब एक सतत दृष्टिकोण:

require(plyr) 
no_lines = 4 
correct_length = 4 
file_con = file("test.csv", "r") 
result = ldply(1:no_lines, function(line) { 
    dum = strsplit(readLines(file_con, n = 1), split = ";")[[1]] 
    if(length(dum) == correct_length) { 
    return(dum) 
    } else { 
    cat(sprintf("Skipped line %s\n", line)) 
    return(NULL) 
    } 
    }) 
close(file_con) 

> result 
    V1 V2 V3 V4 
1 1 2 3 4 
2 1 2 3 4 
3 1 2 3 4 

इस बेशक के रूप में एक छोटी सी उदाहरण है फ़ाइल वास्तव में छोटी है। आइए बेंचमार्क के रूप में कार्य करने के लिए एक और चुनौतीपूर्ण उदाहरण बनाएं।

# First file with invalid rows 
norow = 10e5 # number of rows 
no_lines = round(runif(norow, min = 3, max = 4)) 
no_lines[1] = correct_length 
file_content = ldply(no_lines, function(line) paste(1:line, collapse = ";")) 
writeLines(paste(file_content[[1]], sep = "\n"), "big_test.csv") 

# Same length with valid rows 
file_content = ldply(rep(4, norow), function(line) paste(1:line, collapse = ";")) 
writeLines(paste(file_content[[1]], sep = "\n"), "big_normal.csv") 
बेंचमार्क

# Iterative approach 
system.time({file_con <- file("big_test.csv", "r") 
    result_test <- ldply(1:norow, function(line) { 
     dum = strsplit(readLines(file_con, n = 1), split = ";")[[1]] 
     if(length(dum) == correct_length) { 
     return(dum) 
     } else { 
     # Commenting this speeds up by 30% 
     #cat(sprintf("Skipped line %s\n", line)) 
     return(NULL) 
     } 
     }) 
    close(file_con)}) 
    user system elapsed 
20.559 0.047 20.775 

# Normal read.table 
system.time(result_normal <- read.table("big_normal.csv", sep = ";")) 
    user system elapsed 
    1.060 0.015 1.079 

# read.table with fill = TRUE 
system.time({result_fill <- read.table("big_test.csv", sep = ";", fill=TRUE) 
      na_rows <- complete.cases(result_fill) 
      result_fill <- result_fill[-na_rows,]}) 
    user system elapsed 
    1.161 0.033 1.203 

# Specifying which type the columns are (e.g. character or numeric) 
# using the colClasses argument. 
system.time({result_fill <- read.table("big_test.csv", sep = ";", fill=TRUE, 
             colClasses = rep("numeric", 4)) 
      na_rows <- complete.cases(result_fill) 
      result_fill <- result_fill[-na_rows,]}) 
    user system elapsed 
    0.933 0.064 1.001 

के लिए

अब तो पुनरावृत्ति दृष्टिकोण काफ़ी धीमी है, लेकिन 1 लाख पंक्तियों के लिए 20 सेकंड स्वीकार्य हो सकता है (हालांकि यह स्वीकार्य की अपनी परिभाषा पर निर्भर करता है)। विशेष रूप से जब आपको केवल एक बार यह करना होता है, और इसे बाद में पुनर्प्राप्ति के लिए save का उपयोग करके सहेजने से बचाया जाता है। @Paolo द्वारा सुझाया गया समाधान read.table पर सामान्य कॉल के जितना तेज़ है। पंक्तियां जिनमें कॉलम की गलत मात्रा होती है (इस प्रकार NA) complete.cases का उपयोग करके समाप्त हो जाते हैं। यह निर्दिष्ट करना कि कौन से वर्ग कॉलम आगे प्रदर्शन में सुधार कर रहे हैं, और मुझे लगता है कि कॉलम और पंक्तियों की मात्रा बड़ी हो जाने पर यह प्रभाव बड़ा होगा।

तो निष्कर्ष में, सबसे अच्छा विकल्प fill = TRUE साथ read.table उपयोग करने के लिए, स्तंभों की कक्षाओं को निर्दिष्ट करते हुए है। ldply का उपयोग करने वाला पुनरावृत्ति दृष्टिकोण केवल एक अच्छा विकल्प है यदि आप लाइनों को पढ़ने के तरीके में अधिक लचीलापन चाहते हैं, उदा। केवल एक सीमा को थ्रेसहोल्ड से ऊपर होने पर ही लाइन पढ़ें। लेकिन शायद यह आर में सभी डेटा पढ़ने और एक सबसेट बनाने से जल्दी किया जा सकता है। केवल तभी जब डेटा आपकी रैम से बड़ा होता है, तो मैं इसकी योग्यता वाले पुनरावृत्ति दृष्टिकोण की कल्पना कर सकता हूं।

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