当文本有逗号时,readcsv

时间:2016-06-16 21:00:28

标签: r csv

我正在尝试将成千上万的csv文件读入R中,但是当我的文字有逗号时,我遇到了很多麻烦。

我的csv文件有16列标题。第1列中的一些文字有逗号。第2列是一个字符串,第3列始终是一个数字。

例如,第1列中的条目是: “我不认识罗伯特,金,或道格拉斯” - 马库斯。 A. Ten,Inc总裁

当我尝试

df <- do.call("rbind", lapply(paste(CSVpath, fileNames, sep=""), read.csv, header=TRUE, stringsAsFactors=TRUE, row.names=NULL))

我得到一个超过16列的df,上面的文本被分成4列:

V1                        V2      V3                               V4
"I do not know Robert     Kim     or Douglas" - Marcus. A. Ten     Inc President

当我在一列中需要它时:

V1
"I do not know Robert, Kim, or Douglas"- Marcus. A. Ten, Inc President

1 个答案:

答案 0 :(得分:1)

首先,如果您可以控制数据输出格式,我强烈建议您(a)正确引用字段,或(b)使用另一个字符作为分隔符(例如,tab,pipe“|”)。这是理想的解决方案,因为它肯定会加速未来的处理并“修复故障”,可以这么说。

缺少这一点,您可以尝试以编程方式修复所有行。假设只有第一列是有问题的(即,所有其他列都是完美定义的),那么逐行,将true-separators更改为不同的分隔符(例如,管道或标签)。

对于这个例子,我有4个用逗号分隔的列,我将把合法的分隔符更改为管道。

  1. 一些数据和魔术常数:

    txt <- '"I do not know Robert, Kim, or Douglas" - Marcus. A. Ten, Inc President,TRUE,0,14
    "Something, else",FALSE,1,15
    "Something correct",TRUE,2,22
    Something else,FALSE,3,33'
    nColumns <- 4 # known a priori
    oldsep <- ","
    newsep <- "|"
    

    在您的情况下,您将阅读数据:

    txt <- readLines("path/to/malformed.csv")
    nColumns <- 16
    
  2. 执行手册(基于文本,不解析数据类型)分离:

    splits <- strsplit(readLines(textConnection(txt)), oldsep)
    

    意识到这会将错误字段读取为逐字符"FALSE",而不是布尔数据类型。如果我们接受read.csv和表兄弟完成的魔法类型检测,可以避免

  3. 每行:首先忽略最后nColumns-1个字段,取第一个字段并将它们与旧分隔符重新组合,生成一个字段(带逗号);现在将其与剩余的nColumns-1字段组合,并将它们与新分隔符结合使用。 (顺便说一句:确保我们也正确处理引用双引号。)

    txt2 <- sapply(splits, function(vec) {
      n <- length(vec)
      if (n < nColumns) return(paste(vec, collapse = newsep))
      vec1 <- paste(vec[1:(n - nColumns + 1)], collapse = oldsep)
      vec1 <- sprintf('"%s"', gsub('"', '""', vec1))
      paste(c(vec1,
              vec[(n - nColumns + 2):n]), collapse = newsep)
    })
    txt2[1]
    # [1] "\"\"\"I do not know Robert, Kim, or Douglas\"\" - Marcus. A. Ten, Inc President\"|TRUE|0|14"
    

    (如果原始文件正确引用双引号,则可能不需要sprintf行...但是如果它具有正确的引用,那么我们就不会在第一行中出现此问题的地方。)

  4. 现在,要么直接将数据吸收到data.frame:

    read.csv(textConnection(txt2), header = FALSE, sep = newsep)
    #                                                                        V1    V2 V3 V4
    # 1 "I do not know Robert, Kim, or Douglas" - Marcus. A. Ten, Inc President  TRUE  0 14
    # 2                                                       "Something, else" FALSE  1 15
    # 3                                                     "Something correct"  TRUE  2 22
    # 4                                                          Something else FALSE  3 33
    

    或将这些文章写回文件(如果您想在其他地方处理这些文件,那就很好),并在适当的时候添加con = "path/to/filename

    writeLines(txt2)
    # """I do not know Robert, Kim, or Douglas"" - Marcus. A. Ten, Inc President"|TRUE|0|14
    # """Something, else"""|FALSE|1|15
    # """Something correct"""|TRUE|2|22
    # "Something else"|FALSE|3|33
    

    (两个值得注意的变化:正确的逗号分隔符现在是管道,所有其他逗号仍然是逗号;并且双引号附近有正确的引号。是的,转义双引号只是两个双引号。如果一个字段中有引号,这就是R所期望的。)

  5. 注意:虽然这似乎适用于我的伪造数据(我希望它能与你合作),但你并没有听到人们以这种方式表达R的速度和效率。有 肯定 更好的方法,可能使用python,awk或sed。在R中可能有更快的方法。