Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何有条件地删除write.csv中的引号?_R_Csv - Fatal编程技术网

如何有条件地删除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
>