5

我从事数据清洗。我有一个函数可以识别大输入文件中的坏行(考虑到我的 ram 大小,太大而无法一次读取)并将坏行的行号作为向量返回badRows。这个功能似乎有效。

我现在正试图将坏行读入数据框中,但到目前为止没有成功。

我目前的方法是read.table在与我的文件的打开连接上使用,使用行数向量在读取的每一行之间跳过。对于连续的坏行,此数字为零。

我计算skipVec为:

(badRowNumbers - c(0, badRowNumbers[1:(length(badRowNumbers-1]))-1

但目前我只是将我的函数交给一个skipVec全零的向量。

如果我的逻辑是正确的,这应该返回所有行。它不是。相反,我得到一个错误:

“read.table 中的错误(con,skip = pass,nrow = 1,header = TRUE,sep = “”):输入中没有可用的行”

我当前的函数大致基于 Miron Kursa(“mbq”)的函数,我在这里找到了它。

我的问题与那个问题有些重复,但我认为他的功能有效,所以我以某种方式打破了它。我仍在尝试了解打开文件和打开文件连接之间的区别,我怀疑问题出在某处,或者在我使用lapply.

我在 RStudio 0.97.551 下运行 R 3.0.1,在一台带有 3gig 内存的老旧 Windows XP SP3 机器上运行。石器时代,我知道。

这是产生上述错误消息的代码:

# Make a small small test data frame, write it to a file, and read it back in 
# a row at a time.
testThis.DF <- data.frame(nnn=c(2,3,5), fff=c("aa", "bb", "cc"))  
testThis.DF 

# This function will work only if the number of bad rows is not too big for memory
write.table(testThis.DF, "testThis.DF")
con<-file("testThis.DF")
open(con)
skipVec <- c(0,0,0)
badRows.DF  <- lapply(skipVec, FUN=function(pass){
  read.table(con, skip=pass, nrow=1, header=TRUE, sep="") })
close(con)

错误发生在关闭命令之前。如果我将 readLines 命令从 lapply 和函数中拉出并自行插入,我仍然会遇到相同的错误。

4

1 回答 1

5

如果您不直接运行,而是手动read.table运行lapply前几次迭代,您将看到发生了什么:

> read.table(con, skip=0, nrow=1, header=TRUE, sep="")
  nnn fff
1   2  aa
> read.table(con, skip=0, nrow=1, header=TRUE, sep="")
  X2 X3 bb
1  3  5 cc

因为header = TRUE在每次迭代时读取的不是一行而是两行,所以你最终用完行的速度比你想象的要快,这里是第三次迭代:

> read.table(con, skip=0, nrow=1, header=TRUE, sep="")
Error in read.table(con, skip = 0, nrow = 1, header = TRUE, sep = "") : 
  no lines available in input

现在这可能仍然不是解决您的问题的一种非常有效的方法,但这是您可以修复当前代码的方法:

write.table(testThis.DF, "testThis.DF")
con <- file("testThis.DF")
open(con)
header <- scan(con, what = character(), nlines = 1, quiet = TRUE)
skipVec <- c(0,1,0)
badRows <- lapply(skipVec, function(pass){
  line <- read.table(con, nrow = 1, header = FALSE, sep = "",
                     row.names = 1)
  if (pass) NULL else line
  })
badRows.DF <- setNames(do.call(rbind, badRows), header)
close(con)

提高速度的一些线索:

  1. 使用scan而不是read.table. 仅在最后读取数据,character将数据放入字符矩阵或 data.frame 后,应用于type.convert每一列。
  2. 如果它更短,而不是循环skipVec,循环它。rle因此,您将能够一次阅读或跳过大块的行。
于 2013-10-06T03:34:06.257 回答