[这是一篇文章中的多个错误报告/功能请求,但它们并不一定是孤立的。事先向怪物发帖道歉。根据help(data.table)的建议在此处发布。另外,我是R的新手;如果我在下面的代码中没有遵循最佳实践,那么道歉。我正在努力。]
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个变量,分隔符。
fread
可以接受多个文件名吗?无论如何,我认为这里更好的方法是允许fread将文件作为文件名的向量:
files <- c("my", "files", "to be", "appended")
dt <- fread(files)
据推测,你可以在引擎盖下提高内存效率,而不必像R的用户那样同时保留所有这些对象。
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个。)
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
来提供适当的强制数据。
答案 0 :(得分:6)
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)
并将输出发送给我。我不认为它是文件的大小,而是关于类型和内容的东西。你是对的fread
和rbindlist
在你的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}}快速的原因与首先看到整个输入是相辅相成的。