R:如何使用 fread 函数读入文件并跳过有错误的行?
R: How to read in file and skip lines that have errors with fread function?
我正在尝试使用 fread 函数读取 CSV 文件,但在读取时它打破了行中额外字符的原因。所以我想知道是否有一种方法可以读取文件,跳过有错误的行,然后继续读取它?谢谢你的任何建议。
下面,你可以看到我得到的错误
在 fread("data.csv", :
在第 617854 行提前停止。预期有 52 个字段但找到了 54 个。考虑 fill=TRUE 和 comment.char=。第一个丢弃的非空行:
我认为您可以使用 fread
的 nrows
和 skip
参数来自己做这件事。我没有适当损坏的 csv 来测试它,所以不能保证这会起作用,但可能类似于下面的东西。这基本上是尝试自动获取警告中标记的行号,并在该行 之后恢复读取所有行的 csv。
基本上我一次读取 100,000 行,如果成功,我将该数据写入名为 data_chunks
的 list
。如果它抛出警告,我会选择警告消息,使用一些正则表达式找出行号,然后阅读该行。然后我 return 那 data.table
并写入 data_chunks
列表。然后,我通过 data_chunks
中所有 data.table
的行数加上问题行数(我 return a bad_row
来更新 rows_to_skip
值布尔值与 data.table
一起表示这一点,并在每次迭代时将其添加到 bad_rows
)。
全部在while
循环中,所以会一直执行直到rows_to_skip
的数量超过要读取的行数,在这种情况下,会抛出一个错误并且if
语句触发 break
,然后退出循环。最后,使用 rbindlist
将列表中的所有行绑定在一起。这感觉很老套,可能不是那么可靠,但为了将数据加载到 R 中,它至少是一个开始:
data_chunks <- list()
i <- 1
rows_to_skip <- 0
rows_to_read <- 100000
bad_rows <- 0
file_name <- "my.csv"
while (TRUE) {
out <- tryCatch(
list(
data = data.table::fread(file_name, nrows = rows_to_read, skip = rows_to_skip, header = FALSE),
bad_row = FALSE
),
error = function(e) {
e
},
warning = function(w) {
warn_msg <- conditionMessage(w)
warn_matches <- regexec("line (\d+)", warn_msg)
rows_to_read <- as.numeric(regmatches(warn_msg, warn_matches)[[1]][2]) - 1
if (!is.na(rows_to_read)) {
list(
data = data.table::fread(file_name, nrows = rows_to_read, skip = rows_to_skip, header = FALSE),
bad_row = TRUE
)
} else {
NULL
}
})
if ("error" %in% class(out) || is.null(out)) {
break
} else {
data_chunks[[i]] <- out[["data"]]
}
bad_rows <- bad_rows + out[["bad_row"]]
rows_to_skip <- sum(sapply(data_chunks, nrow)) + bad_rows
i <- i + 1
}
mydata <- data.table::rbindlist(data_chunks, use.names = FALSE)
我正在尝试使用 fread 函数读取 CSV 文件,但在读取时它打破了行中额外字符的原因。所以我想知道是否有一种方法可以读取文件,跳过有错误的行,然后继续读取它?谢谢你的任何建议。 下面,你可以看到我得到的错误
在 fread("data.csv", : 在第 617854 行提前停止。预期有 52 个字段但找到了 54 个。考虑 fill=TRUE 和 comment.char=。第一个丢弃的非空行:
我认为您可以使用 fread
的 nrows
和 skip
参数来自己做这件事。我没有适当损坏的 csv 来测试它,所以不能保证这会起作用,但可能类似于下面的东西。这基本上是尝试自动获取警告中标记的行号,并在该行 之后恢复读取所有行的 csv。
基本上我一次读取 100,000 行,如果成功,我将该数据写入名为 data_chunks
的 list
。如果它抛出警告,我会选择警告消息,使用一些正则表达式找出行号,然后阅读该行。然后我 return 那 data.table
并写入 data_chunks
列表。然后,我通过 data_chunks
中所有 data.table
的行数加上问题行数(我 return a bad_row
来更新 rows_to_skip
值布尔值与 data.table
一起表示这一点,并在每次迭代时将其添加到 bad_rows
)。
全部在while
循环中,所以会一直执行直到rows_to_skip
的数量超过要读取的行数,在这种情况下,会抛出一个错误并且if
语句触发 break
,然后退出循环。最后,使用 rbindlist
将列表中的所有行绑定在一起。这感觉很老套,可能不是那么可靠,但为了将数据加载到 R 中,它至少是一个开始:
data_chunks <- list()
i <- 1
rows_to_skip <- 0
rows_to_read <- 100000
bad_rows <- 0
file_name <- "my.csv"
while (TRUE) {
out <- tryCatch(
list(
data = data.table::fread(file_name, nrows = rows_to_read, skip = rows_to_skip, header = FALSE),
bad_row = FALSE
),
error = function(e) {
e
},
warning = function(w) {
warn_msg <- conditionMessage(w)
warn_matches <- regexec("line (\d+)", warn_msg)
rows_to_read <- as.numeric(regmatches(warn_msg, warn_matches)[[1]][2]) - 1
if (!is.na(rows_to_read)) {
list(
data = data.table::fread(file_name, nrows = rows_to_read, skip = rows_to_skip, header = FALSE),
bad_row = TRUE
)
} else {
NULL
}
})
if ("error" %in% class(out) || is.null(out)) {
break
} else {
data_chunks[[i]] <- out[["data"]]
}
bad_rows <- bad_rows + out[["bad_row"]]
rows_to_skip <- sum(sapply(data_chunks, nrow)) + bad_rows
i <- i + 1
}
mydata <- data.table::rbindlist(data_chunks, use.names = FALSE)