आप जो कर सकते हैं वह फ़ाइल में लाइनों पर फिर से चलना है, और केवल उन पंक्तियों को जोड़ना जिनमें सही लंबाई है।
मैं निम्नलिखित परीक्षण 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
का उपयोग करने वाला पुनरावृत्ति दृष्टिकोण केवल एक अच्छा विकल्प है यदि आप लाइनों को पढ़ने के तरीके में अधिक लचीलापन चाहते हैं, उदा। केवल एक सीमा को थ्रेसहोल्ड से ऊपर होने पर ही लाइन पढ़ें। लेकिन शायद यह आर में सभी डेटा पढ़ने और एक सबसेट बनाने से जल्दी किया जा सकता है। केवल तभी जब डेटा आपकी रैम से बड़ा होता है, तो मैं इसकी योग्यता वाले पुनरावृत्ति दृष्टिकोण की कल्पना कर सकता हूं।
आपकी परिभाषा में क्या बुरा है? –
कोई कारण नहीं है कि आप सीधे 'read.table' का उपयोग नहीं कर रहे हैं? इसमें कई "खराब" वर्णों को चुनने और अनदेखा करने के लिए बहुत सारे तर्क हैं। अपूर्ण पंक्तियों को "भरने" के लिए भी एक तर्क है, यदि यह समस्या है तो आपके पास समस्या है। –