2014-02-15 132 views
2

我有一个大的CSV文件的双打(1000万乘500),我只想读取此文件的几千行(在1和10之间的各个位置百万),由长度为1000万的二进制向量V定义,如果我不想读取该行,则假设值为0,如果我想读取该行,则假设值为1如何读取具有fread函数的CSV文件的特定行

如何从data.table包获取io功能fread来执行此操作?我问,因为fread与其他所有io方法相比如此之快。

最好的解决这个问题,Reading specific rows of large matrix data file,给出了如下的解决方案:

read.csv(pipe(paste0("sed -n '" , paste0(c(1 , which(V == 1) + 1) , collapse = "p; ") , "p' C:/Data/target.csv" , collapse = "")) , head=TRUE)

其中C:/Data/target.csv是大的CSV文件和V01载体中。

不过,我已经注意到,这比简单地对整个矩阵使用fread较慢的订单,即使V只等于1为行总数的一小部分。

因此,由于整个矩阵上的fread将主导上述解决方案,因此如何将fread(特别是fread)与行采样相结合?

这不是重复的,因为它只是关于功能fread

这里是我的问题设置:

#create csv 
csv <- do.call(rbind,lapply(1:50,function(i) { rnorm(5) })) 
#my csv has a header: 
colnames(csv) <- LETTERS[1:5] 
#save csv 
write.csv(csv,"/home/user/test_csv.csv",quote=FALSE,row.names=FALSE) 
#create vector of 0s and 1s that I want to read the CSV from 
read_vec <- rep(0,50) 
read_vec[c(1,5,29)] <- 1 #I only want to read in 1st,5th,29th rows 
#the following is the effect that I want, but I want an efficient approach to it: 
csv <- read.csv("/home/user/test_csv.csv") #inefficient! 
csv <- csv[which(read_vec==1),] #inefficient! 
#the alternative approach, too slow when scaled up! 
csv <- fread(pipe(paste0("sed -n '" , paste0(c(1 , which(read_vec == 1) + 1) , collapse = "p; ") , "p' /home/user/test_csv.csv" , collapse = "")) , head=TRUE) 
#the fastest approach yet still not optimal because it needs to read all rows 
require(data.table) 
csv <- data.matrix(fread('/home/user/test_csv.csv')) 
csv <- csv[which(read_vec==1),] 

回答

3

这种方法需要一个载体v(对应于你的read_vec),确定行读的序列,喂养那些顺序调用fread(...),并rbinds结果一起。

如果你想要的行随机分布在整个文件中,这可能不会更快。但是,如果行在块中(例如,c(1:50, 55, 70, 100:500, 700:1500)),那么将会有很少的电话打到fread(...),您可能会看到显着的改进。

# create sample dataset 
set.seed(1) 
m <- matrix(rnorm(1e5),ncol=10) 
csv <- data.frame(x=1:1e4,m) 
write.csv(csv,"test.csv") 
# s: rows we want to read 
s <- c(1:50,53, 65,77,90,100:200,350:500, 5000:6000) 
# v: logical, T means read this row (equivalent to your read_vec) 
v <- (1:1e4 %in% s) 

seq <- rle(v) 
idx <- c(0, cumsum(seq$lengths))[which(seq$values)] + 1 
# indx: start = starting row of sequence, length = length of sequence (compare to s) 
indx <- data.frame(start=idx, length=seq$length[which(seq$values)]) 

library(data.table) 
result <- do.call(rbind,apply(indx,1, function(x) return(fread("test.csv",nrows=x[2],skip=x[1])))) 
+0

这看起来很有希望。谢谢。 – user2763361

+0

好方法。花了一些时间来了解基本的R“应用”功能,但这是一个很棒的学习@jlhoward –