【问题标题】:How much RAM (memory) do I save by using an array in R (instead of list, data.frame, data.table)?通过使用 R 中的数组(而不是列表、data.frame、data.table)可以节省多少 RAM(内存)?
【发布时间】:2015-11-13 21:17:57
【问题描述】:

描述这种节省/差异的一般公式是什么?

计算需要考虑的项目:

  • 数组维数(标识列)
  • 每个维度的大小(每个标识列中的唯一元素)
  • 维度大小的乘积(数组元素的数量,上述的唯一组合)
  • 每个维度的每个元素的class(),当以二维而不是数组格式存储时(字符、整数、整数64、因子、双精度,很可能还有其他)

我正在为 R 包(半内部包)中的函数编写文档,我想充分描述这一点。根据我(或你!)可以在这里提出的建议,我什至可以编写一个函数来计算这种差异,这样用户就可以在两种方式都尝试之前看到节省的成本(数据集非常大!)。

编辑:

# starting object  
d2 <- data.table(v=rnorm(10)) 
d2[,c("a","b","d","e"):=replicate(4, sample(1:20, 10), simplify=FALSE)]
setkey(d2, a, b, d, e)

# two casts to compare
d2.cast <- d2[CJ(a,b,d,e)] # 2D structure
dN.cast <- reshape2::acast(d2, a~b~d~e, value.var="v") # N-D structure

# compare sizes
print(object.size(d2.cast), units="Kb")
print(object.size(dN.cast), units="Kb")

打印(object.size(d2.cast), units="Kb")
236.4 KB
打印(object.size(dN.cast),单位=“Kb”)
81 KB

如果我使用了糟糕的术语,请更正它。我想更好地描述这种情况:)

【问题讨论】:

  • 这可能有用:adv-r.had.co.nz/memory.html
  • 另外array 似乎有点小,但没那么多。只是一个简单的测试:object.size(lapply(1:100, function(i) lapply(1:100, function(j) rnorm(100))))object.size(array(rnorm(100^3), dim = c(100, 100, 100)))。 (分别为 8484840 和 8000208 字节)。
  • @Molx 请参阅澄清编辑,并附有示例。 2D 对象要大得多,因为它必须通过定义数组的维度来重复仅声明一次的信息。
  • 与 Jan 的回答相反,我想说:使用正确的工具来完成这项工作。如果您正在执行矩阵代数,则最好使用数组。如果您关心内存但不使用矩阵代数,也许您应该这样做。每当你有类似于观察的东西时使用 data.table,尤其是当你有分类/分组变量时。并在适当的地方使用列表或简单向量。所有这些类都便于分析。我不会将此作为答案发布,因为它本质上只是一种意见。
  • 我在 data.table 中做所有事情,直到我需要将事情传递给 Stan 或 JAGS 以进行更多分析。需要 0,但在那些语言中,必须跳过 NA,所以我必须提前定义这些节点(嗯,我基本上需要对它们进行建模)。要点:我使用 data.table,但是当我去进行统计时,AFAIK 使用数组是有意义的。可以做 2D 的事情,但是在 2D 中分解出所有的 0 和 NA 效率很低。

标签: arrays r dataframe data.table data.cube


【解决方案1】:

您应该能够通过prod(dim(ar)) * 字节数来计算数组的大小。
如果您的数据必须保留所有交叉维度的值(因此 data.table 中的 CJ)并且只有一个度量值,那么最好使用数组。
另一方面,拥有二维数据,您可以从所有冗余维度交叉中删除 NA 值。它可以显着减少所需的 RAM 量,在许多情况下允许多维数据扩展到足以进行分析。
与数组不同,2D 建模数据可以存储多个度量值。
2D 在分区和分布式计算方面看起来更友好。

所以它完全取决于数据,但在大多数情况下,IMO 数组根本无法扩展,而 2D 表或 星型模式 2D 表集可以很好地扩展。
如果您想更深入地了解这一点,可以查看我的开发包 data.cube,该包旨在使用 star schema 建模的 data.table 扩展多维数据。


另外将星型模式定义为存储和处理多维数据的简单工具。

星型模式的中心对象,一个事实表

#      prod_name  time_date geog_abb amount     value
# 1: AMC Javelin 2010-01-02       AK  23.64 5193.2088
# 2: AMC Javelin 2010-01-02       MD  88.02 1559.0968

指的是 3D 数组,其中维度是产品时间和地理,以及两个度量。
数组不驱动维度的属性层次结构,它只是字符自然键或整数索引。
表格结构允许为事实表中的每个维度键创建查找表。
生成3维表:

$dims$product
#              prod_name prod_cyl prod_vs prod_am prod_gear
# 1:         AMC Javelin        8       0       0         3
# 2:  Cadillac Fleetwood        8       0       0         3

$dims$time
#     time_date time_month time_month_name time_quarter time_quarter_name time_year
# 1: 2010-01-01          1         January            1                Q1      2010
# 2: 2010-01-02          1         January            1                Q1      2010

$dims$geography
#    geog_abb      geog_name geog_division_name geog_region_name
# 1:       AK         Alaska            Pacific             West
# 2:       AL        Alabama East South Central            South
# 3:       AR       Arkansas West South Central            South

稍后在访问数据时,您可以参考更高级别的属性来分析您的数据,该工具会自动处理连接。
这是基本的星型模式,也是从所有维度的叉积中删除 NA 值的简单方法。
在每个维度中定义层次结构后,您可以做更多事情。
data.cube 包中,您可以使用populate_star(1e5) 生成销售事实表和5 个维度。


最后一节的包 vignette Subset multidimensional data 中提供的内存消耗测试很少。

【讨论】:

  • 也许你可以为“星型模式”提供一个参考......?我没听说过。不错的网站,顺便说一句:)
  • @Frank 我已经编辑了答案,如果有不清楚的地方请告诉我:)
  • 非常感谢。我只记得数据库设计中的“规范化”。您在这里描述的星型模式也大致(我认为)我组织数据的方式。
  • 使用 data.table 的快速连接,我们可以将数据标准化为雪花模式,因此将每个维度级别放在自己的表中。这需要更多的连接,它还减少了维度表的大小。
  • 我实际上需要 NA 值。其中一些成为 0(物种出现数据),其他是真正的 NA。 0 是需要建模的数据,而 NA 有时也是需要建模的缺失值。我正在将此对象传递给 JAGS 或 Stan。
猜你喜欢
  • 2017-02-14
  • 2014-03-19
  • 2012-07-14
  • 1970-01-01
  • 2016-07-20
  • 2012-09-06
  • 1970-01-01
  • 1970-01-01
  • 2017-11-20
相关资源
最近更新 更多