R:如何用Arrow/Parquet将多维数组保存到磁盘?

8yoxcaq7  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(94)

在R中,我想以跨平台格式将一个多维数组(比如10维或更多维,每个维可能有不同的长度)保存到磁盘中。由于这个原因,我排除了.rds文件和saveRDS()
如果可能的话,我想使用箭头或 parquet 格式,从arrow package,但我找不到正确的方式来保存一个数组。使用arrow::write_feather()_parquet会出现错误“No method for as_arrow_table() for object of class array”。
我发现了几个问题,如thisthisthis,它们涉及到将数组保存到磁盘的一般问题,但似乎没有问题或答案使用箭头格式。也许这不可能?

lymnna71

lymnna711#

*注意: 本讨论主要是关于 parquet 格式,它在几个方面与羽毛格式不同。我相信这两个结论是一样的,但我没有太多的羽毛经验,不知道它们是一样的。

https://parquet.apache.org

  • Apache Parquet是一种开源的、面向列的数据文件格式。*

面向列(在其他文档中称为“列”)实际上只是一个框架。
矩阵可以在转换为帧后存储:

matrix(1:20, nrow = 4) |>
  as.data.frame() |>
  arrow::write_parquet("mtx.pq")
arrow::read_parquet("mtx.pq")
# # A tibble: 4 × 5
#      V1    V2    V3    V4    V5
#   <int> <int> <int> <int> <int>
# 1     1     5     9    13    17
# 2     2     6    10    14    18
# 3     3     7    11    15    19
# 4     4     8    12    16    20

为了在那里获得更多的维度,你需要重新塑造它的存储。这将受益于一些 parquet 的效率,但你不会得到“权力”的 parquet 过滤以同样的方式;值得注意的是,找到原始数据的特定切片/平面/子阵列将花费更多的工作和翻译。

ary <- array(1:24, dim=2:4)
arylong <- as.data.frame.table(ary)
arylong[,-ncol(arylong)] <- lapply(arylong[,-ncol(arylong),drop=FALSE], function(z) match(z, unique(z)))
arylong
#    Var1 Var2 Var3 Freq
# 1     1    1    1    1
# 2     2    1    1    2
# 3     1    2    1    3
# 4     2    2    1    4
# 5     1    3    1    5
# 6     2    3    1    6
# 7     1    1    2    7
# 8     2    1    2    8
# 9     1    2    2    9
# 10    2    2    2   10
# 11    1    3    2   11
# 12    2    3    2   12
# 13    1    1    3   13
# 14    2    1    3   14
# 15    1    2    3   15
# 16    2    2    3   16
# 17    1    3    3   17
# 18    2    3    3   18
# 19    1    1    4   19
# 20    2    1    4   20
# 21    1    2    4   21
# 22    2    2    4   22
# 23    1    3    4   23
# 24    2    3    4   24
arrow::write_parquet(arylong, "ary.pq")
arrow::read_parquet("ary.pq")
# # A tibble: 24 × 4
#     Var1  Var2  Var3  Freq
#    <int> <int> <int> <int>
#  1     1     1     1     1
#  2     2     1     1     2
#  3     1     2     1     3
#  4     2     2     1     4
#  5     1     3     1     5
#  6     2     3     1     6
#  7     1     1     2     7
#  8     2     1     2     8
#  9     1     2     2     9
# 10     2     2     2    10
# # ℹ 14 more rows
# # ℹ Use `print(n = ...)` to see more rows

我包含了lapply(..)步骤,因为as.data.frame.table的默认操作是使用Var#作为 * 因子 * 索引,即Var1c(A, B, A, B, ...)。保留这些当然是好的,但我认为对于数组的数字索引的最接近的翻译,最好坚持使用数字。
从数组索引到this的基本转换可能是这样的:

ary[1:2,2:3,3:4]
# , , 1
#      [,1] [,2]
# [1,]   15   17
# [2,]   16   18
# , , 2
#      [,1] [,2]
# [1,]   21   23
# [2,]   22   24

library(dplyr)
pqlong <- arrow::open_dataset("ary.pq") |>
  filter(Var1 %in% 1:2, Var2 %in% 2:3, Var3 %in% 3:4) |>
  arrange() |>
  collect()
newary <- array(dim = sapply(pqlong[,-ncol(pqlong),drop=FALSE], function(z) length(unique(z))))
pqlong[,-ncol(pqlong),drop=FALSE] <- lapply(pqlong[,-ncol(pqlong),drop=FALSE], function(z) match(z, unique(z)))
newary[as.matrix(pqlong[,-ncol(pqlong),drop=FALSE])] <- pqlong[[ncol(pqlong)]]
newary
# , , 1
#      [,1] [,2]
# [1,]   15   17
# [2,]   16   18
# , , 2
#      [,1] [,2]
# [1,]   21   23
# [2,]   22   24
all.equal(newary, ary[1:2,2:3,3:4], check.attributes = FALSE)
# [1] TRUE

备注:

  • 我使用open_dataset来表明这种机制可以很好地处理较大的数组数据集,您只需要提取其中的一小部分,并且不希望将所有数据都加载到RAM中。加载一个大的框架,然后重新整形,实际上会使数组/表的大小增加一倍。因此,dplyrarrow在传递内存结果之前可以很好地进行延迟过滤/加载。(然而,由于dplyr也只适用于帧,所以我不知道如何逻辑地/懒惰地进行整形。
  • 我们使用length(unique(z))是因为我们需要先验地知道newary的目标维数。
  • match(z, unique(z))步骤是必需的,因为矩阵索引将返回(例如)Var2的值2和3,但newary列索引应该是1和2,因此我们将返回值与唯一值匹配,以便适合newary

额外的好处:这也适用于稀疏数据(即使目标数组不是真正的稀疏有效矩阵):

pqlong <- arrow::open_dataset("ary.pq") |>
  filter(Var1 %in% 1:2, Var2 %in% 2:3, Var3 %in% 3:4,
         !Freq %in% c(18, 22)) |>                       # NEW
  arrange() |> collect()

newary <- array(dim = sapply(pqlong[,-ncol(pqlong),drop=FALSE], function(z) length(unique(z))))
pqlong[,-ncol(pqlong),drop=FALSE] <- lapply(pqlong[,-ncol(pqlong),drop=FALSE], function(z) match(z, unique(z)))
newary[as.matrix(pqlong[,-ncol(pqlong),drop=FALSE])] <- pqlong[[ncol(pqlong)]]
newary
# , , 1
#      [,1] [,2]
# [1,]   15   17
# [2,]   16   NA
# , , 2
#      [,1] [,2]
# [1,]   21   23
# [2,]   NA   24

相关问题