Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 快速读取非常大的表作为数据帧_R_Import_Dataframe_R Faq - Fatal编程技术网

R 快速读取非常大的表作为数据帧

R 快速读取非常大的表作为数据帧,r,import,dataframe,r-faq,R,Import,Dataframe,R Faq,我有非常大的表(3000万行),我想在R中作为dataframes加载。read.table()有很多方便的特性,但在实现中似乎有很多逻辑会减慢速度。在我的例子中,我假设我提前知道列的类型,表中不包含任何列标题或行名称,也不包含任何我必须担心的病理字符 我知道使用scan()以列表的形式读取表格可能非常快,例如: datalist <- scan('myfile',sep='\t',list(url='',popularity=0,mintime=0,maxtime=0))) datal

我有非常大的表(3000万行),我想在R中作为dataframes加载。
read.table()
有很多方便的特性,但在实现中似乎有很多逻辑会减慢速度。在我的例子中,我假设我提前知道列的类型,表中不包含任何列标题或行名称,也不包含任何我必须担心的病理字符

我知道使用
scan()
以列表的形式读取表格可能非常快,例如:

datalist <- scan('myfile',sep='\t',list(url='',popularity=0,mintime=0,maxtime=0)))

datalist几年后的更新

这个答案是老生常谈的,而R则继续前进。调整运行速度有点小好处。你的选择是:

  • 使用tidyverse软件包
    vroom
    将csv/制表符分隔文件中的数据直接导入到文件中。看

  • 在中用于将csv/tab分隔文件中的数据直接导入R。请参阅

  • 在中使用(从2015年4月起在CRAN上使用)。这与上面的
    fread
    非常相似。链接中的自述文件解释了这两个函数之间的差异(
    readr
    目前声称比
    data.table::fread
    “慢1.5-2倍”)

  • from提供了快速读取CSV文件的第三个选项

  • 尝试在数据库中存储尽可能多的数据,而不是平面文件。(作为一种更好的永久存储介质,数据以二进制格式从R传递到R,速度更快。)在包中,如中所述,将数据导入临时SQLite数据库,然后将其读入R。另请参见:包,反之则取决于页面的部分。为您提供了一种数据类型,它假装是数据帧,但实际上是一个MonetDB,从而提高了性能。使用其函数导入数据。允许您直接使用存储在多种类型数据库中的数据

  • 以二进制格式存储数据也有助于提高性能。使用
    saveRDS
    /
    readRDS
    (见下文),或HDF5格式的软件包,或从软件包中使用
    write\u fst
    /
    read\u fst


  • 原始答案

    无论是使用read.table还是scan,都有一些简单的方法可以尝试

  • 设置
    nrows
    =数据中的记录数(
    scan
    中的
    nmax

  • 确保
    comment.char=”“
    关闭注释解释

  • 使用
    read.table
    中的
    colClasses
    明确定义每列的类

  • 设置
    multi.line=FALSE
    也可以提高扫描性能

  • 如果这些都不起作用,那么使用其中的一条来确定哪些线正在减慢速度。也许您可以根据结果编写一个精简版的
    read.table

    另一种选择是在将数据读入R之前过滤数据

    或者,如果问题是您必须定期读取数据,则使用这些方法读取一次数据,然后将数据帧保存为二进制blob with,然后下次您可以使用
    readRDS

    更快地检索数据,这是以前的做法,因此值得回顾

    有一个建议是使用
    readChar()
    ,然后使用
    strsplit()
    substr()
    对结果进行字符串操作。您可以看到readChar中涉及的逻辑远小于read.table

    我不知道记忆是否是一个问题,但你也可能。这是一个MapReduce框架,设计用于处理大型数据集。为此,您将使用hsTableReader函数。这是一个示例(但它有一个学习Hadoop的学习曲线):


    str我最初没有看到这个问题,几天后又问了一个类似的问题。我要记下我前面的问题,但我想在这里添加一个答案来解释我是如何使用
    sqldf()
    来实现这一点的

    目前已经有了将2GB或更多文本数据导入R数据帧的最佳方法。昨天我写了一篇关于使用
    sqldf()
    将数据导入SQLite作为暂存区域,然后将数据从SQLite吸入R的文章。这对我来说非常有效。我能够在<5分钟内提取2GB(3列,40mm行)的数据。相比之下,
    read.csv
    命令运行了一夜,从未完成

    以下是我的测试代码:

    设置测试数据:

    bigdf <- data.frame(dim=sample(letters, replace=T, 4e7), fact1=rnorm(4e7), fact2=rnorm(4e7, 20, 50))
    write.csv(bigdf, 'bigdf.csv', quote = F)
    

    bigdf奇怪的是,尽管这是一个重要的问题--
    data.frame
    s只是具有正确属性的列表,但多年来一直没有人回答这个问题的底部部分,因此如果您有大量数据,您就不想将
    用作.data.frame
    或类似的列表。简单地将列表“转换”为数据框要快得多:

    attr(df, "row.names") <- .set_row_names(length(df[[1]]))
    class(df) <- "data.frame"
    

    attr(df,“row.names”)这里是一个利用
    data.table中的
    fread
    的示例

    这些示例来自帮助页面,指向
    fread
    ,并在我的windows XP Core 2 duo E8400上计时

    library(data.table)
    # Demo speedup
    n=1e6
    DT = data.table( a=sample(1:1000,n,replace=TRUE),
                     b=sample(1:1000,n,replace=TRUE),
                     c=rnorm(n),
                     d=sample(c("foo","bar","baz","qux","quux"),n,replace=TRUE),
                     e=rnorm(n),
                     f=sample(1:1000,n,replace=TRUE) )
    DT[2,b:=NA_integer_]
    DT[4,c:=NA_real_]
    DT[3,d:=NA_character_]
    DT[5,d:=""]
    DT[2,e:=+Inf]
    DT[3,e:=-Inf]
    
    标准读表
    一个值得一提的补充要点。如果您有一个非常大的文件,您可以使用(其中
    bedGraph
    是工作目录中的文件名)动态计算行数(如果没有标题):

    然后,您可以在
    read.csv
    read.table
    中使用它

    >system.time((BG=read.table(bedGraph, nrows=numRow, col.names=c('chr', 'start', 'end', 'score'),colClasses=c('character', rep('integer',3)))))
       user  system elapsed 
     25.877   0.887  26.752 
    >object.size(BG)
    203949432 bytes
    

    通常我认为将较大的数据库保存在数据库中(例如Postgres)是一种很好的做法。我不使用比(nrow*ncol)ncell=10M大太多的东西,这是非常小的;但我经常发现,当我从多个数据库进行查询时,我只希望R创建并保存内存密集型图。在未来的32GB笔记本电脑中,其中一些类型的内存问题将消失
    system.time(big.df <- read.csv('bigdf.csv'))
    
    attr(df, "row.names") <- .set_row_names(length(df[[1]]))
    class(df) <- "data.frame"
    
    library(data.table)
    # Demo speedup
    n=1e6
    DT = data.table( a=sample(1:1000,n,replace=TRUE),
                     b=sample(1:1000,n,replace=TRUE),
                     c=rnorm(n),
                     d=sample(c("foo","bar","baz","qux","quux"),n,replace=TRUE),
                     e=rnorm(n),
                     f=sample(1:1000,n,replace=TRUE) )
    DT[2,b:=NA_integer_]
    DT[4,c:=NA_real_]
    DT[3,d:=NA_character_]
    DT[5,d:=""]
    DT[2,e:=+Inf]
    DT[3,e:=-Inf]
    
    write.table(DT,"test.csv",sep=",",row.names=FALSE,quote=FALSE)
    cat("File size (MB):",round(file.info("test.csv")$size/1024^2),"\n")    
    ## File size (MB): 51 
    
    system.time(DF1 <- read.csv("test.csv",stringsAsFactors=FALSE))        
    ##    user  system elapsed 
    ##   24.71    0.15   25.42
    # second run will be faster
    system.time(DF1 <- read.csv("test.csv",stringsAsFactors=FALSE))        
    ##    user  system elapsed 
    ##   17.85    0.07   17.98
    
    system.time(DF2 <- read.table("test.csv",header=TRUE,sep=",",quote="",  
                              stringsAsFactors=FALSE,comment.char="",nrows=n,                   
                              colClasses=c("integer","integer","numeric",                        
                                           "character","numeric","integer")))
    
    
    ##    user  system elapsed 
    ##   10.20    0.03   10.32
    
    require(data.table)
    system.time(DT <- fread("test.csv"))                                  
     ##    user  system elapsed 
    ##    3.12    0.01    3.22
    
    require(sqldf)
    
    system.time(SQLDF <- read.csv.sql("test.csv",dbname=NULL))             
    
    ##    user  system elapsed 
    ##   12.49    0.09   12.69
    
    # sqldf as on SO
    
    f <- file("test.csv")
    system.time(SQLf <- sqldf("select * from f", dbname = tempfile(), file.format = list(header = T, row.names = F)))
    
    ##    user  system elapsed 
    ##   10.21    0.47   10.73
    
     require(ff)
    
     system.time(FFDF <- read.csv.ffdf(file="test.csv",nrows=n))   
     ##    user  system elapsed 
     ##   10.85    0.10   10.99
    
    ##    user  system elapsed  Method
    ##   24.71    0.15   25.42  read.csv (first time)
    ##   17.85    0.07   17.98  read.csv (second time)
    ##   10.20    0.03   10.32  Optimized read.table
    ##    3.12    0.01    3.22  fread
    ##   12.49    0.09   12.69  sqldf
    ##   10.21    0.47   10.73  sqldf on SO
    ##   10.85    0.10   10.99  ffdf
    
    >numRow=as.integer(system(paste("wc -l", bedGraph, "| sed 's/[^0-9.]*\\([0-9.]*\\).*/\\1/'"), intern=T))
    
    >system.time((BG=read.table(bedGraph, nrows=numRow, col.names=c('chr', 'start', 'end', 'score'),colClasses=c('character', rep('integer',3)))))
       user  system elapsed 
     25.877   0.887  26.752 
    >object.size(BG)
    203949432 bytes
    
    # Looking at Voter/Registrant Age by Decade
    
    library(RPostgreSQL);library(lattice)
    
    con <- dbConnect(PostgreSQL(), user= "postgres", password="password",
                     port="2345", host="localhost", dbname="WC2014_08_01_2014")
    
    Decade_BD_1980_42 <- dbGetQuery(con,"Select PrecinctID,Count(PrecinctID),extract(DECADE from Birthdate) from voterdb where extract(DECADE from Birthdate)::numeric > 198 and PrecinctID in (Select * from LD42) Group By PrecinctID,date_part Order by Count DESC;")
    
    Decade_RD_1980_42 <- dbGetQuery(con,"Select PrecinctID,Count(PrecinctID),extract(DECADE from RegistrationDate) from voterdb where extract(DECADE from RegistrationDate)::numeric > 198 and PrecinctID in (Select * from LD42) Group By PrecinctID,date_part Order by Count DESC;")
    
    with(Decade_BD_1980_42,(barchart(~count | as.factor(precinctid))));
    mtext("42LD Birthdays later than 1980 by Precinct",side=1,line=0)
    
    with(Decade_RD_1980_42,(barchart(~count | as.factor(precinctid))));
    mtext("42LD Registration Dates later than 1980 by Precinct",side=1,line=0)
    
    data_frame <- fread("filename.csv",sep=",",header=FALSE,stringsAsFactors=FALSE,select=c(1,4,5,6,7),colClasses=c("as.numeric","as.character","as.numeric","as.Date","as.Factor"))
    
    package                 read    print   sample   filter  aggregate   total
    read.delim              1m      21.5s   1ms      315ms   764ms       1m 22.6s
    readr                   33.1s   90ms    2ms      202ms   825ms       34.2s
    data.table              15.7s   13ms    1ms      129ms   394ms       16.3s
    vroom (altrep) dplyr    1.7s    89ms    1.7s     1.3s    1.9s        6.7s
    
    library(dplyr)
    library(tibble)
    library(OpenRepGrid)
    
    n <- 1000000
    
    set.seed(1234)
    some_levels1 <- sapply(1:10, function(x) paste(LETTERS[sample(1:26, size = sample(3:8, 1), replace = TRUE)], collapse = ""))
    some_levels2 <- sapply(1:65, function(x) paste(LETTERS[sample(1:26, size = sample(5:16, 1), replace = TRUE)], collapse = ""))
    
    
    test_data <- mtcars %>%
      rownames_to_column() %>%
      sample_n(n, replace = TRUE) %>%
      mutate_all(~ sample(., length(.))) %>%
      mutate(factor1 = sample(some_levels1, n, replace = TRUE),
             factor2 = sample(some_levels2, n, replace = TRUE),
             text = randomSentences(n, sample(3:8, n, replace = TRUE))
             )
    
    library(arrow)
    
    write_parquet(test_data , "test_data.parquet")
    
    # you can also mess with the compression
    write_parquet(test_data, "test_data2.parquet", compress = "gzip", compression_level = 9)
    
    read_parquet("test_data.parquet")
    
    # this option will result in lightning fast reads, but in a different format.
    read_parquet("test_data2.parquet", as_data_frame = FALSE)
    
    read_fwf(arquivos[i],col_types = "ccccccc",fwf_cols(cnpj = c(4,17), nome = c(19,168), cpf = c(169,183), fantasia = c(169,223), sit.cadastral = c(224,225), dt.sitcadastral = c(226,233), cnae = c(376,382)))