【问题标题】:Quickly reading very large tables as dataframes快速读取非常大的表作为数据框
【发布时间】:2024-04-14 21:55:02
【问题描述】:

我有非常大的表(3000 万行),我想将它们作为数据帧加载到 R 中。read.table() 有很多方便的功能,但在实现中似乎有很多逻辑可以放慢速度。就我而言,我假设我提前知道列的类型,表格不包含任何列标题或行名,并且没有任何我需要担心的病态字符。

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

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

但我尝试将其转换为数据帧的一些尝试似乎将上述性能降低了 6 倍:

df <- as.data.frame(scan('myfile',sep='\t',list(url='',popularity=0,mintime=0,maxtime=0))))

有没有更好的方法来做到这一点?或者很可能完全不同的方法来解决这个问题?

【问题讨论】:

    标签: r import dataframe r-faq


    【解决方案1】:

    几年后的更新

    这个答案已经过时了,R 已经继续前进了。调整read.table 以使其运行得更快一点,并没有什么好处。您的选择是:

    1. 使用 tidyverse 包 vroom 中的 vroom 将数据从 csv/tab 分隔文件直接导入 R tibble。见Hector's answer

    2. data.table 中使用fread 将数据从csv/制表符分隔的文件直接导入R。请参阅mnel's answer

    3. readr 中使用 read_table(从 2015 年 4 月起在 CRAN 上使用)。这很像上面的fread。链接中的 readme 解释了这两个函数之间的区别(readr 目前声称比 data.table::fread 慢“1.5-2 倍”)。

    4. read.csv.raw from iotools 提供了快速读取 CSV 文件的第三个选项。

    5. 尽量在数据库而不是平面文件中存储尽可能多的数据。 (作为一种更好的永久存储介质,数据以二进制格式传入和传出 R,速度更快。)sqldf 包中的read.csv.sql,如JD Long's answer 中所述,将数据导入临时SQLite 数据库,然后将其读入 R。另请参阅:RODBC 包,以及DBI package 页面的反向依赖部分。 MonetDB.R 为您提供了一种伪装成数据框但实际上是底层 MonetDB 的数据类型,从而提高了性能。使用其monetdb.read.csv 函数导入数据。 dplyr 允许您直接处理存储在多种类型数据库中的数据。

    6. 以二进制格式存储数据也有助于提高性能。使用 saveRDS/readRDS(见下文)、h5rhdf5 包用于 HDF5 格式,或 write_fst/read_fst 来自 fst 包。


    原答案

    无论您使用 read.table 还是 scan,都可以尝试一些简单的事情。

    1. 设置nrows=数据中的记录数scan 中的nmax)。

    2. 确保comment.char="" 关闭对cmets 的解释。

    3. read.table 中使用colClasses 显式定义每一列的类。

    4. 设置multi.line=FALSE 还可以提高扫描性能。

    如果这些都不起作用,则使用profiling packages 之一来确定哪些行正在减慢速度。或许你可以根据结果写一个read.table的精简版。

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

    或者,如果问题是你必须定期读取它,那么使用这些方法读取数据一次,然后将数据帧保存为二进制blob save @ 987654344@,那么下次您可以使用 load readRDS 更快地检索它。

    【讨论】:

    • 感谢里奇的建议。我做了一些测试,似乎使用 read.table 的 nrow 和 colClasses 选项获得的性能相当有限。例如,读取约 7M 行表需要 78 秒(不带选项)和 67 秒(带选项)。 (注意:该表有 1 个字符列,4 个整数列,我使用 comment.char='' 和 stringsAsFactors=FALSE 读取)。尽可能使用 save() 和 load() 是一个很好的技巧 - 一旦使用 save() 存储,同一个表只需 12 秒即可加载。
    • “feather”包有一种新的二进制格式,可以很好地与 Python 的 pandas 数据帧配合使用
    • 我想也许你需要再次更新你的帖子关于包feather。对于读取数据featherfread 快得多。例如,在我刚刚加载的 4GB 数据集上,read_featherfread 快了大约 4.5 倍。对于保存数据fwrite 仍然更快。 blog.dominodatalab.com/the-r-data-i-o-shootout
    • 但是feather的文件大小比RDS大得多。我认为它不支持压缩。 RDS 文件为 216 MB,羽毛文件为 4GB。所以feather 的阅读速度更快,但它使用更多的存储空间。
    • @Zboson 如果您需要将数据帧存储在可以从 R 和 Python 访问的文件中,那么 feather 是一个不错的选择。如果您只关心能够在 R 中读取数据,rds 更可取。
    【解决方案2】:

    这之前是asked on R-Help,因此值得回顾。

    有一个建议是使用readChar(),然后使用strsplit()substr() 对结果进行字符串操作。可以看到readChar所涉及的逻辑比read.table少很多。

    我不知道这里是否存在内存问题,但您也可以want to take a look at the HadoopStreaming package。这个uses Hadoop,这是一个为处理大型数据集而设计的 MapReduce 框架。为此,您将使用 hsTableReader 函数。这是一个示例(但它有学习 Hadoop 的学习曲线):

    str <- "key1\t3.9\nkey1\t8.9\nkey1\t1.2\nkey1\t3.9\nkey1\t8.9\nkey1\t1.2\nkey2\t9.9\nkey2\"
    cat(str)
    cols = list(key='',val=0)
    con <- textConnection(str, open = "r")
    hsTableReader(con,cols,chunkSize=6,FUN=print,ignoreKey=TRUE)
    close(con)
    

    这里的基本思想是将数据导入分解成块。您甚至可以使用其中一种并行框架(例如 snow)并通过对文件进行分段来并行运行数据导入,但很可能对于大型数据集无济于事,因为您会遇到内存限制,这就是为什么 map-reduce 是更好的方法。

    【讨论】:

    • 我刚刚做了一个快速测试,由于某些莫名其妙的原因,readChar 似乎比 readLines 快得多。但是,与简单的 C 测试相比,它仍然很慢。在读取 100 兆的简单任务中,R 比 C 慢 5 - 10 倍
    • 不明白你的意思。 Hadoop 的重点是处理非常大的数据,这就是问题所在。
    • 尽管名称如此,hsTableReader 本身与 Hadoop 没有任何关系,它是用于处理大数据的碎片。它一次从 con 读取一大块行,并将每个块作为 data.frame 传递给 FUN 进行处理。使用 ignoreKey=FALSE,它会根据键(第一列中的条目)进行一些额外的分组,这与 Map/Reduce 方法相关。
    • 嗨。您将如何将此 Hadoop 数据用作其他包(例如 zoo,旨在同时与所有数据一起使用)的输入?
    【解决方案3】:

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

    little bit of discussion 关于将 2GB 或更多文本数据导入 R 数据帧的最佳方法。昨天我写了一篇blog post,关于使用sqldf() 将数据导入SQLite 作为暂存区,然后将其从SQLite 吸入R。这对我来说非常有效。我能够在 5 分钟内提取 2GB(3 列,40 毫米行)的数据。相比之下,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)
    

    我在运行以下导入例程之前重新启动了 R:

    library(sqldf)
    f <- file("bigdf.csv")
    system.time(bigdf <- sqldf("select * from f", dbname = tempfile(), file.format = list(header = T, row.names = F)))
    

    我让以下行运行了一整夜,但它从未完成:

    system.time(big.df <- read.csv('bigdf.csv'))
    

    【讨论】:

    • 嗨。您将如何将它用作其他包(例如 zoo,旨在同时与所有数据一起使用)的输入?
    • @skan 最终对象是一个数据框。因此,您必须将其转换为 zoo 对象才能与 zoo 一起使用。查看 zoo 文档中的示例以获取说明。
    • @JD Long。嗨,问题是当您将其转换为动物园对象时,它会尝试将其放入内存中。如果它太大,则会产生错误。如果 zoo 对象的结果(例如两个系列的聚合)也是如此,它也需要是 sql 或 ff 对象。
    • 不知道sqldf有什么问题。我在磁盘上创建了一个简单的 1GB 文件(带有 2 个数字列)并使用 DTSQL
    • @what m 是千所以 mm 是一万或百万。我可能应该将其大写为 MM。但我发现,如果你有足够多样化的受众,几乎任何一百万个缩写都会让某人感到困惑。我试图过于冗长,很抱歉我让它变得更加混乱! accountingcoach.com/blog/what-does-m-and-mm-stand-for
    【解决方案4】:

    奇怪的是,多年来没有人回答这个问题的底部,尽管这是一个重要的问题——data.frames 只是具有正确属性的列表,所以如果你有大量数据,你不想使用as.data.frame 或类似列表。简单地将列表“就地”“转换”为数据框要快得多:

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

    这不会复制数据,因此它是即时的(与所有其他方法不同)。它假定您已经在列表中相应地设置了names()

    [至于将大数据加载到 R 中——就我个人而言,我将它们按列转储到二进制文件中并使用readBin()——这是迄今为止最快的方法(除了 mmaping),并且仅受磁盘速度的限制。与二进制数据相比,解析 ASCII 文件本身就很慢(即使在 C 中也是如此)。]

    【讨论】:

    • 使用tracmem 建议attr&lt;-class&lt;- 在内部进行复制。 bit::setattrdata.table::setattr 不会。
    • 也许你用错了顺序?如果您使用df=scan(...); names(df)=...; attr...; class...,则没有副本 - 请参阅tracemem()(在 R 2.15.2 中测试)
    • 能否详细说明如何将大数据按列转储到二进制文件中?
    【解决方案5】:

    这是一个使用来自data.table 1.8.7 的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]
    

    标准读表

    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
    

    优化的 read.table

    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
    

    fread

    require(data.table)
    system.time(DT <- fread("test.csv"))                                  
     ##    user  system elapsed 
    ##    3.12    0.01    3.22
    

    sqldf

    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
    

    ff / ffdf

     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
    

    【讨论】:

    • 很好的答案,并且基准测试在其他情况下也成立。使用fread 在一分钟内读入一个 4GB 的文件。曾尝试使用基本 R 函数读取它,大约花了 15 个小时。
    • 我的基准测试表明 data.table 中的 read.csv 具有更大的速度优势。请注意,data.table 不是标准的 R,但(遗憾的是)“只是”由其创建者在 CRAN 上很好地共享。它甚至被认为不够标准,无法制作通用的 R 包列表,更不用说有资格作为数据帧的替代品了。它有很多优点,但也有一些非常违反直觉的方面。您可能希望将 as.data.frame(fread.csv("test.csv")) 与包一起使用以返回标准 R 数据框世界。
    • @mnel 你能重新运行基准测试并包含readr吗?
    • 第二个@jangorecki。此外,鉴于 fread 现在有一些真正的竞争对手,添加基准以优化 fread 使用可能很有用——指定 colClasses 等。
    • @jangorecji @MichaelChirico 给出的代码是完全可复制的,因此可以直接模拟阅读器...重新运行代码,在我的机器上运行的时间是大多数结果的两倍,即使不是更多,尽管我正在通过网络运行它(以及更新的版本,因为它已经有一段时间了)......并且使用 readr 我在 7 秒,但当我第二次运行(0.66 秒)时也不到一秒,我怀疑有一些缓存或网络中的一些瓶颈。此处显示的最快解决方案的 fread 是我这边的 2 秒进行比较(第一次以 8.69 秒运行),由于某种原因较慢)
    【解决方案6】:

    还有一点值得一提。如果您有一个非常大的文件,您可以使用(其中bedGraph 是您工作目录中文件的名称)即时计算行数(如果没有标题):

    >numRow=as.integer(system(paste("wc -l", bedGraph, "| sed 's/[^0-9.]*\\([0-9.]*\\).*/\\1/'"), intern=T))
    

    然后您可以在 read.csvread.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
    

    【讨论】:

      【解决方案7】:

      通常我认为将较大的数据库保存在数据库中只是一种好习惯(例如 Postgres)。我不使用任何大于 (nrow * ncol) ncell = 10M 的东西,它非常小;但我经常发现我希望 R 仅在从多个数据库查询时创建和保存内存密集型图。在 32 GB 笔记本电脑的未来,其中一些类型的内存问题将消失。但是使用数据库来保存数据然后使用 R 的内存来生成查询结果和图表的吸引力仍然可能是有用的。一些优点是:

      (1) 数据保持加载在您的数据库中。当您重新打开笔记本电脑时,您只需在 pgadmin 中重新连接到您想要的数据库。

      (2) 确实,R 可以比 SQL 执行更多漂亮的统计和图形操作。但我认为 SQL 比 R 更适合用于查询大量数据。

      # 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)
      

      【讨论】:

      • DuckDB 是一个相对较新的开源分析数据库,现在可在 CRAN 上使用。非常小的包,同时支持类似 SQL 命令的 PostGres。还支持用SQL命令查询parquet格式文件。
      【解决方案8】:

      我觉得 fread 是一个更快的函数,而不是传统的 read.table。 指定附加属性,例如仅选择所需的列、指定 colclasses 和 string 作为因素将减少导入文件所需的时间。

      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"))
      

      【讨论】:

        【解决方案9】:

        另一种方法是使用vroom 包。现在在 CRAN 上。 vroom 不会加载整个文件,它会索引每条记录所在的位置,并在以后使用时读取。

        只为你使用的东西付费。

        参见Introduction to vroomGet started with vroomvroom benchmarks

        基本的概述是大文件的初始读取会快得多,随后对数据的修改可能会稍微慢一些。所以根据你的用途,它可能是最好的选择。

        请看下面vroom benchmarks 的简化示例,关键部分是超快的读取时间,但聚合等操作稍显逊色。

        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
        

        【讨论】:

          【解决方案10】:

          我正在使用新的arrow 包快速读取数据。它似乎处于相当早期的阶段。

          具体来说,我使用的是 parquet 柱状格式。这将转换回 R 中的 data.frame,但如果不这样做,您可以获得更深的加速。这种格式很方便,因为它也可以在 Python 中使用。

          我的主要用例是在相当受限的 RShiny 服务器上。由于这些原因,我更喜欢将数据附加到应用程序(即 SQL 之外),因此需要小文件大小和速度。

          这篇链接的文章提供了基准测试和很好的概述。我在下面引用了一些有趣的观点。

          https://ursalabs.org/blog/2019-10-columnar-perf/

          文件大小

          也就是说,Parquet 文件的大小甚至是压缩后的 CSV 文件的一半。 Parquet 文件如此之小的原因之一是字典编码(也称为“字典压缩”)。与使用通用字节压缩器(如 LZ4 或 ZSTD(用于 FST 格式))相比,字典压缩可以产生更好的压缩。 Parquet 旨在生成非常小的文件,并且可以快速读取。

          读取速度

          当按输出类型进行控制时(例如,将所有 R data.frame 输出相互比较),我们看到 Parquet、Feather 和 FST 的性能彼此相差较小。 pandas.DataFrame 输出也是如此。 data.table::fread 与 1.5 GB 文件大小相比具有令人印象深刻的竞争力,但在 2.5 GB CSV 上却落后于其他文件。


          独立测试

          我对 1,000,000 行的模拟数据集执行了一些独立的基准测试。基本上我改变了一堆东西来尝试挑战压缩。我还添加了一个包含随机单词和两个模拟因素的简短文本字段。

          数据

          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)
          

          我针对一些竞争选项测试了读取此数据的结果,得到的结果与上述文章略有不同,这是预期的。

          这个文件远没有基准文章那么大,所以也许这就是区别。

          测试

          • rds: test_data.rds (20.3 MB)
          • parquet2_native:(14.9 MB,压缩率更高,as_data_frame = FALSE
          • parquet2: test_data2.parquet(14.9 MB,压缩率更高)
          • 镶木地板: test_data.parquet (40.7 MB)
          • fst2: test_data2.fst(27.9 MB,更高压缩率)
          • fst: test_data.fst (76.8 MB)
          • fread2: test_data.csv.gz (23.6MB)
          • fread: test_data.csv (98.7MB)
          • feather_arrow: test_data.feather(使用 arrow 读取 157.2 MB)
          • feather: test_data.feather(使用 feather 读取 157.2 MB)

          观察

          对于这个特定的文件,fread 实际上非常快。我喜欢高度压缩的parquet2 测试中的小文件大小。如果我真的需要加快速度,我可能会花时间使用本机数据格式而不是 data.frame

          这里fst也是不错的选择。我会使用高度压缩的fst 格式或高度压缩的parquet,这取决于我是否需要在速度或文件大小之间进行权衡。

          【讨论】:

            【解决方案11】:

            我已经尝试了以上所有方法,[readr][1] 做得最好。我只有 8GB 内存

            循环 20 个文件,每个 5gb,7 列:

            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)))
            

            【讨论】:

              【解决方案12】:

              我想以最简单的形式贡献基于 Spark 的解决方案:

              # Test Data ---------------------------------------------------------------
              
              set.seed(123)
              bigdf <-
                  data.frame(
                      dim = sample(letters, replace = T, 4e7),
                      fact1 = rnorm(4e7),
                      fact2 = rnorm(4e7, 20, 50)
                  )
              tmp_csv <- fs::file_temp(pattern = "big_df", ext = ".csv")
              readr::write_csv(x = bigdf, file = tmp_csv)
              
              # Spark -------------------------------------------------------------------
              
              # Installing if needed
              # sparklyr::spark_available_versions()
              # sparklyr::spark_install()
              
              library("sparklyr")
              sc <- spark_connect(master = "local")
              
              # Uploading CSV
              system.time(tbl_big_df <- spark_read_csv(sc = sc, path = tmp_csv))
              

              Spark 产生了相当不错的结果:

              >> system.time(tbl_big_df <- spark_read_csv(sc = sc, path = tmp_csv))
                 user  system elapsed 
                0.278   0.034  11.747 
              

              这是在 32GB 内存的 MacBook Pro 上测试的。

              备注

              Spark,通常不应该能够“赢得”针对速度优化的软件包。不过,我想使用 Spark 提供答案:

              • 对于某些使用 Spark 无法正常工作的 cmets 和答案可能是一个可行的替代方案
              • 从长远来看,将尽可能多的数据敲入 data.frame 可能会在以后尝试对该对象执行其他操作并达到架构的性能范围时出现问题

              我认为对于此类问题,应考虑处理 1e7 或更多行 Spark 的任务。即使有可能将这些数据“敲入”单个data.frame,它也只是感觉不对。在部署模型等时,该对象可能难以使用并产生问题。

              【讨论】:

                最近更新 更多