使用write.csv
时,可以通过使用quote=FALSE
删除引号来显着减小文件大小(大数据集大约25%)。但是,如果您的数据中存在逗号,则可能会导致read.csv
出现故障。例如:
x <- data.frame(a=1:2,b=c("hello,","world"))
dim(x)
[1] 2 2
f <- tempfile()
write.csv(x,f,row.names=FALSE,quote=FALSE)
dim(read.csv(f))
[1] 2 2
read.csv(f)
a b
1 hello NA
2 world NA
观察列名称错位,丢失数据和添加虚假数据。
是否可以删除引号,但是为数据中包含逗号的字段维护它们?
答案 0 :(得分:6)
我使用的解决方案是@TimPietzcker和@BenBolker的评论的组合。
quote
可以是一个数字向量,用于指定引用哪些列。虽然我希望只在需要时引用,但这几乎可以减少文件大小的缩减(也使用na=""
)。
commas <- which(sapply(x, function(y) any(grepl(",",y))))
write.csv(x,f,row.names=FALSE,quote=commas)
read.csv(f)
a b
1 1 hello,
2 2 world
答案 1 :(得分:3)
这是我对@Bill Denney建议的想法的实现。我觉得它更好一部分因为它更简洁,更容易理解,但主要是因为我写了它:)
##' Write CSV files with quotes same as MS Excel 2013 or newer
##'
##' R inserts quotes where MS EExcel CSV export no longer inserts quotation marks on character
##' variables, except when the cells include commas or quotation marks.
##' This function generates CSV files that are, so far as we know
##' in exactly the same style as MS Excel CSV export files.
##'
##' This works by manually inserting quotation marks where necessary and
##' turning FALSE R's own method to insert quotation marks.
##' @param x a data frame
##' @param file character string for file name
##' @param row.names Default FALSE for row.names
##' @return the return from write.table.
##' @author Paul Johnson
##' @examples
##' set.seed(234)
##' x1 <- data.frame(x1 = c("a", "b,c", "b", "The \"Washington, DC\""),
##' x2 = rnorm(4), stringsAsFactors = FALSE)
##' x1
##' dn <- tempdir()
##' fn <- tempfile(pattern = "testcsv", fileext = ".csv")
##' writeCSV(x1, file = fn)
##' readLines(fn)
##' x2 <- read.table(fn, sep = ",", header = TRUE, stringsAsFactors = FALSE)
##' all.equal(x1,x2)
writeCSV <- function(x, file, row.names = FALSE){
xischar <- colnames(x)[sapply(x, is.character)]
for(jj in xischar){
x[ , jj] <- gsub('"', '""', x[ , jj], fixed = TRUE)
needsquotes <- grep('[\",]', x[ ,jj])
x[needsquotes, jj] <- paste0("\"", x[needsquotes, jj], "\"")
}
write.table(x, file = file, sep = ",", quote = FALSE,
row.names = row.names)
}
示例输出:
> set.seed(234)
> x1 <- data.frame(x1 = c("a", "b,c", "b", "The \"Washington, DC\""),
+ x2 = rnorm(4), stringsAsFactors = FALSE)
> x1
x1 x2
1 a 0.6607697
2 b,c -2.0529830
3 b -1.4992061
4 The "Washington, DC" 1.4712331
> dn <- tempdir()
> fn <- tempfile(pattern = "testcsv", fileext = ".csv")
> writeCSV(x1, file = fn)
> readLines(fn)
[1] "x1,x2"
[2] "a,0.660769736644892"
[3] "\"b,c\",-2.052983003941"
[4] "b,-1.49920605110092"
[5] "\"The \"\"Washington, DC\"\"\",1.4712331168047"
> x2 <- read.table(fn, sep = ",", header = TRUE, stringsAsFactors = FALSE)
> all.equal(x1,x2)
[1] TRUE
>
答案 2 :(得分:2)
如果其他人正在寻找类似的解决方案,我只是写了write.csv
(write.csv.minimal.quote
)的全面替代品,只在绝对需要时才引用:
quote.if.required <- function(x, qmethod=c("double", "escape"), sep=",", eol="\n") {
qmethod <- match.arg(qmethod)
x <- as.character(x)
mask.quote.sub <- grepl('"', x, fixed=TRUE)
mask.quote.sep <-
grepl(sep, x, fixed=TRUE) |
grepl(eol, x, fixed=TRUE)
qstring <- switch(qmethod, escape="\\\\\"", double="\"\"")
x[mask.quote.sub] <-
paste0('"', gsub('"', qstring, x[mask.quote.sub]), '"')
x[mask.quote.sep & !mask.quote.sub] <-
paste0('"', x[mask.quote.sep & !mask.quote.sub], '"')
x
}
write.csv.minimal.quote <- function(x, file="", ..., qmethod=c("double", "escape"), row.names=FALSE, sep=",", eol="\n", quote) {
qmethod <- match.arg(qmethod)
if (!is.data.frame(x)) {
cn <- colnames(x)
x <- as.data.frame(x)
colnames(x) <- cn
} else {
cn <- colnames(x)
}
cn <- quote.if.required(cn,
qmethod=qmethod,
sep=sep,
eol=eol)
x <- as.data.frame(lapply(x, quote.if.required,
qmethod=qmethod,
sep=sep,
eol=eol))
if (is.logical(row.names) && row.names) {
row.names <- quote.if.required(base::row.names(x),
qmethod=qmethod,
sep=sep,
eol=eol)
} else if (is.character(row.names)) {
row.names <- quote.if.required(row.names,
qmethod=qmethod,
sep=sep,
eol=eol)
}
write.table(x, file=file, append=FALSE, sep=",", dec=".", eol="\n", col.names=cn, row.names=row.names, quote=FALSE)
}
#tmp <- data.frame('"abc'=1:3, "def,hij"=c("1,2", "3", '4"5'), klm=6:8)
#names(tmp) <- c('"abc', "def,hij", "klm")
#write.csv.minimal.quote(tmp, file="test.csv")
答案 3 :(得分:1)
如果值包含逗号,则用引号括起来。然后write.csv
与quote = FALSE
。
library(stringr)
options(useFancyQuotes = FALSE)
d <- data.frame(
x = c("no comma", "has,comma")
)
d$x <- with(d, ifelse(str_detect(x, ","), dQuote(x), as.character(x)))
filename <- "test.csv"
write.csv(d, file = filename, quote = FALSE, row.names= FALSE)
noquote(readLines(filename))
## [1] x no comma "has,comma"
read.csv(filename)
## x
## 1 no comma
## 2 has,comma
(如果您愿意,可以将grepl
替换为str_detect
,将paste
替换为dQuote
。)
另一方面,我不相信对于大多数数据集,您可以节省大约25%的文件大小。如果您的目标是小文件,那么您最好压缩文件(请参阅zip
包中的tar
和utils
),或将其存储在二进制文件中(请参阅{{ 1}}和save
包),或者可能在数据库中。