追加多个大数据。表;使用colClasses和fread进行自定义数据强制;命名管道

时间:2014-01-19 17:51:56

标签: r append data.table fread

[这是一篇文章中的多个错误报告/功能请求,但它们并不一定是孤立的。事先向怪物发帖道歉。根据help(data.table)的建议在此处发布。另外,我是R的新手;如果我在下面的代码中没有遵循最佳实践,那么道歉。我正在努力。]

1。 rbindlist在6 * 8GB文件(我有128GB RAM)

上崩溃

首先,我想报告使用rbindlist追加大数据.tables导致R到segfault(ubuntu 13.10,打包的R版本3.0.1-3ubuntu1,从CRAN内部安装的data.table)。机器有128 GiB的RAM;所以,考虑到数据的大小,我不应该耗尽内存。

我的代码:

append.tables <- function(files) {
    moves.by.year <- lapply(files, fread)
    move <- rbindlist(moves.by.year)
    rm(moves.by.year)
    move[,week_end := as.Date(as.character(week_end), format="%Y%m%d")]
    return(move)
}

崩溃讯息:

 append.tables crashes with this:
> system.time(move <- append.tables(files))
 *** caught segfault ***
address 0x7f8e88dc1d10, cause 'memory not mapped'

Traceback:
 1: rbindlist(moves.by.year)
 2: append.tables(files)
 3: system.time(move <- append.tables(files))

共有6个文件,每个文件大约有8个GiB或1亿个行,有8个变量,分隔符。

2。 fread可以接受多个文件名吗?

无论如何,我认为这里更好的方法是允许fread将文件作为文件名的向量:

files <- c("my", "files", "to be", "appended")
dt <- fread(files)

据推测,你可以在引擎盖下提高内存效率,而不必像R的用户那样同时保留所有这些对象。

3。 colClasses给出错误消息

我的第二个问题是我需要为我的某个数据类型指定a custom coercion handler,但是失败了:

dt <- fread(tfile, colClasses=list(date="myDate"))
Error in fread(tfile, colClasses = list(date = "myDate")) : 
  Column name 'myDate' in colClasses not found in data

是的,就日期而言,简单:

    dt[,date := as.Date(as.character(date), format="%Y%m%d")]

作品。

但是,我有一个不同的用例,即在从字符转换之前从其中一个数据列中去除小数点。这里的精度非常重要(因此我们需要使用整数类型),并且从double类型强制转换为整数会导致精度损失。

现在,我可以通过一些system()调用来解决这个问题,以附加文件并通过一些sed魔术(这里简化)来管道它们(其中tfile是另一个临时文件):

if (has_header) {
    tfile2 <- tempfile()
    system(paste("echo fakeline >>", tfile2))
    system(paste("head -q -n1", files[[1]], ">>", tfile2))
    system(paste("tail -q -n+2", tfile2, paste(files, collapse=" "),
                 " | sed 's/\\.//' >>", tfile), wait=wait)
    unlink(tfile2)
} else {
    system(paste("cat", paste(files, collapse=" "), ">>", tfile), wait=wait)
}

但这涉及额外的读/写周期。我有4个TiB数据需要处理,这是一个额外的读写数据(不,不是全部都在一个data.table。大约1000个。)

4。 fread认为命名管道是空文件

我通常会留下wait = TRUE。但我试图通过使tfile成为命名管道system('mkfifo', tfile),设置wait = FALSE,然后运行fread(tfile)来查看是否可以避免额外的读/写周期。然而,fread抱怨管道是一个空文件:

system(paste("tail -q -n+2", tfile2, paste(files, collapse=" "),
             " | sed 's/\\.//' >>", tfile), wait=FALSE)
move <- fread(tfile)
Error in fread(tfile) : File is empty: /tmp/RtmpbxNI1L/file78a678dc1999

无论如何,这有点像黑客。

如果我有我的愿望清单

,简化代码

理想情况下,我可以做这样的事情:

setClass("Int_Price")
setAs("character", "Int_Price",
    function (from) {
        return(as.integer(gsub("\\.", "", from)))
    }
)

dt <- fread(files, colClasses=list(price="Int_Price"))

然后我会有一个很好的长data.table来提供适当的强制数据。

1 个答案:

答案 0 :(得分:6)

更新:rbindlist错误已在commit 1100 v1.8.11中修复。来自新闻:

  

o修复了在> 250m行上发生的罕见段错(在内存分配期间整数溢出);关闭#5305。感谢Guenter J. Hitsch的报道。


如评论中所述,您应该分别提出单独的问题。但是因为他们是如此优秀,并且在最后联系到了愿望,好的,将一气呵成。

<强> 1。 rbindlist崩溃6 * 8GB文件(我有128GB RAM)

请再次运行更改行:

moves.by.year <- lapply(files, fread)

moves.by.year <- lapply(files, fread, verbose=TRUE)

并将输出发送给我。我不认为它是文件的大小,而是关于类型和内容的东西。你是对的freadrbindlist在你的128GB盒子上加载48GB的数据应该没有问题。如你所说,lapply应返回48GB,然后rbindlist应创建一个新的48GB单表。这应该适用于您的128GB机器,因为96GB&lt; 128GB。 1亿行* 6是6亿行,远低于20亿行限制所以应该​​没问题(data.table尚未赶上R3中的长向量支持,否则&gt; 2 ^ 31行将也没关系。)

<强> 2。可以fread接受多个文件名吗?

很棒的主意。如你所说,fread可以扫描所有6个文件,检测它们的类型并计算总行数,首先。然后直接为6亿行分配一次。这将不必要地通过48GB的RAM节省搅拌。它也可能在开始读取第一个文件之前检测到第5或第6个文件中的任何异常(例如),因此在出现问题时会更快地返回。

我会将此作为功能请求提交,并在此处发布链接。

第3。 colClasses给出错误消息

键入list时,类型显示在=的左侧,列名称或位置的向量显示在右侧。这个想法比colClasses read.csv更容易,"character"只接受一个向量;一遍又一遍地保存重复?fread。我可以发誓这在fread(tfile, colClasses=list(date="myDate")) Error in fread(tfile, colClasses = list(date = "myDate")) : Column name 'myDate' in colClasses not found in data 中有更好的记录,但似乎没有。我会看一下。

所以,而不是

fread(tfile, colClasses=list(myDate="date"))

正确的语法是

fread(tfile, colClasses=list(character="date"))  # just fread accepts list

鉴于你在问题中所说的话,你真的想要:

fread(tfile, colClasses=c("date"="character"))   # both read.csv and fread

numeric

其中任何一个都应该将名为“date”的列加载为字符,以便您可以在强制之前对其进行操作。如果真的只是日期,那么我仍然要自动实施这种强制。您提到了integer64的精确度,所以只是为了提醒fread也可以直接读取fread

<强> 4。 fread认为命名管道是空文件

希望现在假设前一点已经解决,这种情况会消失吗? fread通过内存映射其输入来工作。它可以接受非文件,例如http地址和连接(tbc),为方便起见它首先写的是将完整的输入写入ramdisk,以便它可以从那里映射输入。 {{1}}快速的原因与首先看到整个输入是相辅相成的。