如何有条件地删除write.csv中的引号?
使用如何有条件地删除write.csv中的引号?,r,csv,R,Csv,使用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.
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
x如果值包含逗号,请将其括在引号中。然后使用quote=FALSE写入.csv
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
库(stringr)
选项(useFancyQuotes=FALSE)
d我采用的解决方案是将@TimPietzcker和@BenBolker的评论结合起来
quote
可以是数字向量,用于指定引用哪些列。虽然我更愿意只在需要时引用,但在我的情况下,这允许几乎完全减小文件大小(也使用na=”“
)
commas如果其他人正在寻找类似的解决方案,我刚刚编写了一个全面的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")
quote.if.required这是我对@Bill Denney建议的想法的实现。我认为它更好,部分原因是它更简短,对我来说更容易理解,但主要原因是我写了它:)
###“编写CSV文件,并使用与MS Excel 2013或更新版本相同的引号
##'
##'R在MS EExcel CSV导出不再在字符上插入引号的位置插入引号
##'变量,除非单元格中包含逗号或引号。
##'此函数生成CSV文件,据我们所知
##'与MS Excel CSV导出文件的样式完全相同。
##'
##'这通过在必要时手动插入引号和
##'设置为FALSE R将使用自己的方法插入引号。
##“@param x a数据帧
##'@param file文件名的字符串
##“@param row.names row.names的默认值为FALSE
##“@从write.table返回返回。
##“@作者保罗·约翰逊
##“@示例
##'集.种子(234)
##“x1似乎说这是不可能的,除非您事先知道要引用哪些列(“如果[quote
是]数字向量,则其元素将作为要引用的列的索引。”)。其他语言提供“仅在必要时引用”选项,而R似乎没有。也许您可以使用这样的语言(如Python)或类似于的东西(sappy(mydata,function(x)(is.factor(x)| | is.character(x))&&any(grepl(,“x)))对文件进行后期处理
想知道哪些栏目需要保护吗?@TimPietzcker正如你所说,在必要的时候,似乎没有内在的方式来引用,但我使用了你的建议,只引用了受影响的栏目。如果你们中的任何一个想写出来作为答案,我会接受的。谢谢,这正是我所想的,但对于一个大的问题,这是非常巧妙的cols的成员。我采纳了评论中的建议,只引用了受指定为quote
影响的所有列。文件大小减少了几乎一样多。25%有点误导性-它与na=“”
,但我的数据本身至少有20%。你考虑过只做write.csv吗(…,quote=FALSE,sep=“|”)
或类似内容?如果您能找到文本中没有出现的分隔字符,问题就会消失。现在我想,这就是制表符分隔文件存在的原因。这是一个选项,但问题是我无法始终确定数据中会有什么(有一些自由文本字段)。我还必须与其他人沟通,并且需要尽可能保持事情的简单和统一。这是正确的做法。最近,我们遇到了一个问题,即来自R的csv被采用MS Excel方式的进口商拒绝。由于MS Excel改变了他们使用引号的方式,这一直是一个不变的PITA。我将看到如果我能把这一点缩短一点,并与一些R内部人士讨论。我相信R的write.table需要一个引号参数“msexcel”或类似的参数来产生MS行为。只需发布我自己的R函数就可以做到这一点。可以使用您的压力测试。对于发现这一点的其他人,它看起来像readr::write_csv()
实现最小引号。乍一看,您的函数看起来不错。我的想法是:1)除了字符和数字之外,其他类型如何?许多类型(因子、日期等)也可能包含逗号或引号。2)它不能推广到其他分隔符、引号方法、行尾标记等。(这对您的用例可能无关紧要,但我需要它们,因为我有时会生成以制表符分隔的值文件,这些文件也会受益于最小的引用。)3)国际化(包括以逗号表示的备用小数位)怎么样?使用Lappy创建修改的字符串,而不是for循环。使用[
索引数据帧可能会非常慢。
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")
##' 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
>