如何使用fread功能读取CSV文件的特定行

use*_*361 3 csv io performance r

我有一个大的CSV文件,它是double的(1000万乘500),我只想读入该文件的几千行(在1到1000万之间的不同位置),由V长度为1000万的二进制矢量定义,0如果我不想读取该行并且1我确实想读取该行,则假定为value 。

如何freaddata.table包中获取io函数来执行此操作?我问是因为fread与所有其他io方法相比是如此之快。

这个问题的最佳解决方案,读取大型矩阵数据文件的特定行,提供以下解决方案:

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文件,V0或的向量1

但是我已经注意到,这比简单地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),] 
Run Code Online (Sandbox Code Playgroud)

jlh*_*ard 5

此方法采用一个向量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]))))
Run Code Online (Sandbox Code Playgroud)