r - 我们可以使用哪些方法来 reshape 非常大的数据集?

标签 r performance bigdata reshape

当由于非常大的数据计算需要很长时间并且因此我们不希望它们崩溃时,事先知道使用哪种 reshape 方法是很有值(value)的。
最近,在性能方面进一步开发了 reshape 数据的方法,例如data.table::dcasttidyr::spread .特别是 dcast.data.table似乎定下了基调[1] , [2] , [3] ,
[4] .这使得其他方法作为基础 R 的 reshape在基准测试中似乎已经过时并且几乎没用[5] .
理论
然而 , 听说 reshape当涉及到非常大的数据集(可能超过 RAM 的数据集)时,它仍然是无与伦比的,因为它是唯一可以处理它们的方法,因此它仍然有权存在。使用 reshape2::dcast 的相关崩溃报告支持这一点[6] .至少有一个引用资料暗示 reshape()可能确实比 reshape2::dcast 有优势对于真正的“大东西”[7] .
方法
寻求证据,我认为值得花时间做一些研究。所以我用不同大小的模拟数据做了一个基准测试,这些数据越来越耗尽内存来比较 reshape , dcast , dcast.data.table , 和 spread .我查看了具有三列的简单数据集,具有不同的行数以获得不同的大小(参见最底部的代码)。

> head(df1, 3)
  id                 tms         y
1  1 1970-01-01 01:00:01 0.7463622
2  2 1970-01-01 01:00:01 0.1417795
3  3 1970-01-01 01:00:01 0.6993089
RAM 大小仅为 8 GB,这是我模拟“非常大”数据集的阈值。为了使计算的时间保持合理,我对每种方法只进行了 3 次测量,并专注于从长到宽的 reshape 。
结果
unit: seconds
       expr       min        lq      mean    median        uq       max neval size.gb size.ram
1  dcast.DT        NA        NA        NA        NA        NA        NA     3    8.00    1.000
2     dcast        NA        NA        NA        NA        NA        NA     3    8.00    1.000
3     tidyr        NA        NA        NA        NA        NA        NA     3    8.00    1.000
4   reshape 490988.37 492843.94 494699.51 495153.48 497236.03 499772.56     3    8.00    1.000
5  dcast.DT   3288.04   4445.77   5279.91   5466.31   6375.63  10485.21     3    4.00    0.500
6     dcast   5151.06   5888.20   6625.35   6237.78   6781.14   6936.93     3    4.00    0.500
7     tidyr   5757.26   6398.54   7039.83   6653.28   7101.28   7162.74     3    4.00    0.500
8   reshape  85982.58  87583.60  89184.62  88817.98  90235.68  91286.74     3    4.00    0.500
9  dcast.DT      2.18      2.18      2.18      2.18      2.18      2.18     3    0.20    0.025
10    tidyr      3.19      3.24      3.37      3.29      3.46      3.63     3    0.20    0.025
11    dcast      3.46      3.49      3.57      3.52      3.63      3.74     3    0.20    0.025
12  reshape    277.01    277.53    277.83    278.05    278.24    278.42     3    0.20    0.025
13 dcast.DT      0.18      0.18      0.18      0.18      0.18      0.18     3    0.02    0.002
14    dcast      0.34      0.34      0.35      0.34      0.36      0.37     3    0.02    0.002
15    tidyr      0.37      0.39      0.42      0.41      0.44      0.48     3    0.02    0.002
16  reshape     29.22     29.37     29.49     29.53     29.63     29.74     3    0.02    0.002
enter image description here
(注意:基准测试是在配备 Intel Core i5 2.5 GHz、8GB DDR3 RAM 1600 MHz 的辅助 MacBook Pro 上执行的。)
显然,dcast.data.table似乎总是最快的。正如预期的那样,所有打包的方法都以非常大的数据集失败,可能是因为计算超出了 RAM 内存:
Error: vector memory exhausted (limit reached?)
Timing stopped at: 1.597e+04 1.864e+04 5.254e+04
仅限 reshape处理所有数据大小,尽管速度很慢。
结论
封装方法如 dcastspread对于小于 RAM 或计算不会耗尽 RAM 的数据集是非常宝贵的。如果数据集大于 RAM 内存,打包方法将失败,我们应该使用 reshape .
问题
我们可以这样总结吗?有人可以澄清一下为什么 data.table/reshapetidyr方法失败以及它们在方法上与 reshape 的区别是什么? ?海量数据的唯一选择是可靠但速度慢的马reshape ?我们可以从这里未测试的方法中得到什么 tapply , unstack , 和 xtabs接近[8] ,
[9] ?
或者,简而言之:除了reshape,还有什么更快的选择?失败?

数据/代码
# 8GB version
n <- 1e3      
t1 <- 2.15e5  # approx. 8GB, vary to increasingly exceed RAM

df1 <- expand.grid(id=1:n, tms=as.POSIXct(1:t1, origin="1970-01-01"))
df1$y <- rnorm(nrow(df1))

dim(df1)
# [1] 450000000         3

> head(df1, 3)
id                 tms         y
1  1 1970-01-01 01:00:01 0.7463622
2  2 1970-01-01 01:00:01 0.1417795
3  3 1970-01-01 01:00:01 0.6993089

object.size(df1)
# 9039666760 bytes

library(data.table)
DT1 <- as.data.table(df1)

library(microbenchmark)
library(tidyr)
# NOTE: this runs for quite a while!
mbk <- microbenchmark(reshape=reshape(df1, idvar="tms", timevar="id", direction="wide"),
                      dcast=dcast(df1, tms ~ id, value.var="y"),
                      dcast.dt=dcast(DT1, tms ~ id, value.var="y"),
                      tidyr=spread(df1, id, y),
                      times=3L)

最佳答案

如果你的真实数据和你的样本数据一样有规律,我们可以通过注意到 reshape 矩阵实际上只是改变它的 dim 属性来非常有效。

数据非常少的第一名

library(data.table)
library(microbenchmark)
library(tidyr)

matrix_spread <- function(df1, key, value){
  unique_ids <-  unique(df1[[key]])
  mat <- matrix( df1[[value]], ncol= length(unique_ids),byrow = TRUE)
  df2 <- data.frame(unique(df1["tms"]),mat)
  names(df2)[-1] <- paste0(value,".",unique_ids)
  df2
}

n <- 3      
t1 <- 4
df1 <- expand.grid(id=1:n, tms=as.POSIXct(1:t1, origin="1970-01-01"))
df1$y <- rnorm(nrow(df1))

reshape(df1, idvar="tms", timevar="id", direction="wide")
#                    tms        y.1        y.2       y.3
# 1  1970-01-01 01:00:01  0.3518667  0.6350398 0.1624978
# 4  1970-01-01 01:00:02  0.3404974 -1.1023521 0.5699476
# 7  1970-01-01 01:00:03 -0.4142585  0.8194931 1.3857788
# 10 1970-01-01 01:00:04  0.3651138 -0.9867506 1.0920621

matrix_spread(df1, "id", "y")
#                    tms        y.1        y.2       y.3
# 1  1970-01-01 01:00:01  0.3518667  0.6350398 0.1624978
# 4  1970-01-01 01:00:02  0.3404974 -1.1023521 0.5699476
# 7  1970-01-01 01:00:03 -0.4142585  0.8194931 1.3857788
# 10 1970-01-01 01:00:04  0.3651138 -0.9867506 1.0920621

all.equal(check.attributes = FALSE,
          reshape(df1, idvar="tms", timevar="id", direction="wide"),
          matrix_spread (df1, "id", "y"))
# TRUE

然后在更大的数据上

(对不起,我现在不能进行大量计算)
n <- 100      
t1 <- 5000

df1 <- expand.grid(id=1:n, tms=as.POSIXct(1:t1, origin="1970-01-01"))
df1$y <- rnorm(nrow(df1))

DT1 <- as.data.table(df1)

microbenchmark(reshape=reshape(df1, idvar="tms", timevar="id", direction="wide"),
               dcast=dcast(df1, tms ~ id, value.var="y"),
               dcast.dt=dcast(DT1, tms ~ id, value.var="y"),
               tidyr=spread(df1, id, y),
               matrix_spread = matrix_spread(df1, "id", "y"),
               times=3L)

# Unit: milliseconds
# expr                 min         lq       mean     median         uq        max neval
# reshape       4197.08012 4240.59316 4260.58806 4284.10620 4292.34203 4300.57786     3
# dcast           57.31247   78.16116   86.93874   99.00986  101.75189  104.49391     3
# dcast.dt       114.66574  120.19246  127.51567  125.71919  133.94064  142.16209     3
# tidyr           55.12626   63.91142   72.52421   72.69658   81.22319   89.74980     3
# matrix_spread   15.00522   15.42655   17.45283   15.84788   18.67664   21.50539     3 

还不错!

关于内存使用,我猜如果 reshape如果您可以使用我的假设或预处理数据以满足它们,我的解决方案将处理它:
  • 数据排序
  • 我们只有 3 列
  • 对于所有 id 值,我们找到所有 tms 值
  • 关于r - 我们可以使用哪些方法来 reshape 非常大的数据集?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55077668/

    相关文章:

    regex - 使用正则表达式提取 r ngram

    linux - Bash 非常慢

    r - 相当快地保存非常大的 R 数据帧

    hadoop - hive 工作花费太多时间

    r - 这是 group_by 和 lead/lag 中的错误吗?

    c++ - 编译错误,未创建函数/方法!对于 brms 模型

    r - R中按组划分的spearman相关性

    java - JScrollPane 'laggy' 滚动,有很多组件

    python - 爬行速度在接近尾声时急剧减慢

    c++ - 大数据的内存组织