【问题标题】:Load first N rows from an .RData file从 .RData 文件加载前 N 行
【发布时间】:2021-01-03 07:21:24
【问题描述】:

我四处搜索,但找不到我的问题的答案。 像scanbase 包)和freaddata.table 包)这样的函数可以很好地从用户指定的 .txt 或 .csv 中读取前 N 行。但是,当涉及到 .RData 时,load 会加载整个文件,并且无法指定应从中读取多少个值。

我有超过 3GB 大小的 .RData 文件,每个文件都包含一个 data.framedata.table,并且并不总是需要加载整个文件,而只需加载前 100 或 1,000 行的对象。有没有办法做到这一点?

【问题讨论】:

  • 你考虑过readLines() 吗?
  • 如果存储在 RDS 文件中的对象是 data.frame,ReadLines() 的行为会很差。
  • 我认为使用 RData 文件会非常困难。无论如何,您应该使用saveRDS。就个人而言,我会使用fwrite/fread。它们不应该明显变慢。

标签: r dataframe datatable rdata


【解决方案1】:

我的猜测是没有现成的解决方案。

如果我们查看一个示例、ASCII 编码、未压缩的 RDS 文件,我们会看到它以列主顺序存储:

saveRDS(mtcars[1:5, 1:2], "testrds.rds", ascii = TRUE, compress = FALSE)

产生这个文件(我插入了 cmets)

A        ## ASCII file
3        ## some version info and ??
262146
197888
6
CP1252
787
2
14
5       ## This seems to indicate 5 items in this vector (column)
21      ## first column starts here (but how would you know?)
21
22.8
21.4
18.7    ## first column ends here
14
5       ## Again, This seems to indicate 5 items in this vector (column)
6       ## second column starts here
6
4
6
8       ## second column ends here
1026
1
262153    # Attributes start here: names, row.names, class 
5
names                ## col names
16
2
262153
3
mpg                  ### first col name
262153
3
cyl                  ### second col name
1026
1
262153
9
row.names            ## 2nd attribute: row.names 
16
5
262153
9
Mazda\040RX4         ### first row name
262153
13
Mazda\040RX4\040Wag  ### second row name
262153
10
Datsun\040710        ### ...
262153
14
Hornet\0404\040Drive
262153
17
Hornet\040Sportabout ### last row name
1026
1
262153
5
class                ## 3rd attribute: class
16
1
262153
10
data.frame           ### value of class
254

正如您在这个简单的 RDS 文件中看到的那样,读取前几行数据仍然需要解析整个文件,并且需要知道要跳过哪些行。并且您需要比 R Internals 文档中更多的 RDS 文件文档。

基于这个简单的示例,您可能会做出一些猜测并获得一个粗略的函数草案,该函数适用于您知道是数据帧的 RDS 文件,但这需要一些工作 - 如果您愿意,还需要做更多的工作确保它足够健壮以处理更复杂的数据帧(例如,使用factorDate 列)。如果您有 RData 文件,它们将具有类似但稍微复杂一点的格式,因为它们可以处理多个对象。

总而言之,我认为 RDS 和 RData 对于您可能想要部分加载的数据来说是糟糕的选择。您最好使用 CSV 或 TSV,然后您可以使用您在问题中提到的标准选项(或 vroom::vroom)仅将您想要的数据加载到内存中。

【讨论】:

    【解决方案2】:

    试试 read_lines_raw:

    first_1000 <- read_lines_raw(rdata_filename,skip=0,n_max = 1000)
    

    【讨论】:

    • 您能否提供一个示例,您将如何在fil &lt;- tempfile("iris", fileext = ".rds"); saveRDS(iris, fil) 之后继续获得与iris[1:5,] 相同的结果?
    • @JineshEP:谢谢,但是运行您的代码,我得到了未命名的列表,其中包含所有值都表示为十六进制的组件。
    • 检查原始文件上的 infoRDS,它可能是 xdr 二进制表示,read_lines_raw 返回的是原始向量列表,因此取消列出 raw_line 输出并检查它的头部是否与原始文件的头部匹配文件。如果是这样,请尝试对原始行进行反序列化。
    【解决方案3】:

    这个简单的解决方法怎么样?

    my_data <- head(readRDS("my_data.RDS"), n = 1000)
    

    head()n 参数设置为您需要的任何值。

    如果你打算经常这样做,你甚至可以让自己发挥一点作用。

    read_rds <- function(file, n) {
      # note file can either be a connection object or a character string containing a path
      return(head(readRDS(file), n))
    } 
    

    【讨论】:

    • 你没有抓住重点。 OP 希望避免将巨大的对象导入内存。
    • @Ben Norris:Roland 是对的,您提出的解决方案将首先加载整个文件(正是我想要避免的),然后获取数据对象的头部。
    猜你喜欢
    • 1970-01-01
    • 2020-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-12
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    相关资源
    最近更新 更多