【问题标题】:How to read specific rows of CSV file with fread function如何使用 fread 函数读取 CSV 文件的特定行
【发布时间】:2014-03-14 23:15:51
【问题描述】:

我有一个双精度的大 CSV 文件(1000 万乘 500),我只想读取这个文件的几千行(在 1 到 1000 万之间的不同位置),由二进制向量 V 定义长度为 1000 万,如果我不想阅读该行,则假定值为 0,如果我想阅读该行,则假定值为 1

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

这个问题的最佳解决方案,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),] 

【问题讨论】:

    标签: r csv io performance


    【解决方案1】:

    这种方法采用向量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]))))
    

    【讨论】:

    • 这看起来很有希望。谢谢。
    • 好方法。花了一些时间来理解基本 R apply 函数,但这是一个很棒的学习@jlhoward
    猜你喜欢
    • 2019-10-13
    • 1970-01-01
    • 2019-11-13
    • 2020-07-13
    • 2018-06-08
    • 2016-06-02
    • 2023-03-08
    • 1970-01-01
    • 2015-10-25
    相关资源
    最近更新 更多