【发布时间】:2025-12-21 19:10:11
【问题描述】:
这是上一个 Stack Overflow 问题的延续:
Fastest way to read in 100,000 .dat.gz files
我有许多 .dat.gz 文件,但此数据中的许多行都有零值,我想避免将它们带入内存。
为测试用例创建数据:
# Make dir
system("mkdir practice")
require(data.table)
# Function to create data
create_write_data <- function(file.nm) {
dt <- data.table(Day=0:365)
dt[, (paste0("V", 1:17)) := lapply(1:17, function(x) rpois(n=366, 0.1))]
write.table(dt, paste0("./practice/",file.nm), row.names=FALSE, sep="\t", quote=FALSE)
system(paste0("gzip ./practice/", file.nm))
}
这里是应用代码:
# Apply function to create 10 fake zipped data.frames (550 kb on disk)
tmp <- lapply(paste0("dt", 1:10,".dat"), function(x) create_write_data(x))
我的解决方案(不起作用)
之前链接的 Stack Overflow 答案给出了一次读取所有数据的绝佳答案:
tbl = fread('cat ./practice/*dat.gz | gunzip | grep -v "^Day"')
但现在我想过滤第 14 列和第 15 列都不为 0 的数据,因此我创建了以下管道以使用 awk 命令提供给 fread:
command <- "cat ./practice/*dat.gz | gunzip | awk -F, '!/^Day/ && $14 !=0 && $15 != 0'"
fread(command)
但是,这根本没有过滤我的数据。有关如何让 awk 命令在此工作流程中工作的任何想法?
【问题讨论】:
-
将 cmd-1 中的
grep更改为 cmd-2 中的 awk,如...| awk -F, '/^Day/ && $14 !=0 && $15 != 0'"。 (基本上消除了 cmd-2)祝你好运。 -
好的,但我的意思是消除 cmd-2。你为什么需要它?如果 cmd-1 正在使用
grep -v,只需将其替换为修改后的 awk 代码。此时,我会设置一个小测试来确认$14 && $15包含您认为的值。祝你好运。 -
啊,刚刚注意到别的东西,我想你想要
...| gunzip -c | awk...(现在不记得了,甚至可能需要...|gunzip -c - | awk ...。祝你好运。 -
不,这不是 2 次传递数据。它的效率很高。但是之前错过了另一个小优化:您可以进一步简化为
gunzip -c ./path/to/files*.dat.gz | awk ...祝您好运。 -
@Mike.Gahan 您可能希望至少运行一次此命令,以确保您可以假设制表符分隔的数据中没有任何嵌入的制表符。
system2('cat', c('practice/*.dat.gz | gunzip | awk "{print NF}" | sort | uniq -c'))
标签: r awk data.table fread