我正在尝试将成千上万的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
答案 0 :(得分:1)
首先,如果您可以控制数据输出格式,我强烈建议您(a)正确引用字段,或(b)使用另一个字符作为分隔符(例如,tab,pipe“|”)。这是理想的解决方案,因为它肯定会加速未来的处理并“修复故障”,可以这么说。
缺少这一点,您可以尝试以编程方式修复所有行。假设只有第一列是有问题的(即,所有其他列都是完美定义的),那么逐行,将true-separators更改为不同的分隔符(例如,管道或标签)。
对于这个例子,我有4个用逗号分隔的列,我将把合法的分隔符更改为管道。
一些数据和魔术常数:
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
执行手册(基于文本,不解析数据类型)分离:
splits <- strsplit(readLines(textConnection(txt)), oldsep)
意识到这会将错误字段读取为逐字符"FALSE"
,而不是布尔数据类型。如果我们接受read.csv
和表兄弟完成的魔法类型检测,可以避免
每行:首先忽略最后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
行...但是如果它具有正确的引用,那么我们就不会在第一行中出现此问题的地方。)
现在,要么直接将数据吸收到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所期望的。)
注意:虽然这似乎适用于我的伪造数据(我希望它能与你合作),但你并没有听到人们以这种方式表达R的速度和效率。有 肯定 更好的方法,可能使用python,awk或sed。在R中可能有更快的方法。