jay*_*.sf 33 performance r bigdata reshape
当由于非常大的数据计算将花费很长时间并且因此我们不希望它们崩溃时,事先知道要使用哪种重塑方法将很有价值。
最近,关于性能的数据重塑方法已得到进一步发展,例如data.table::dcast
和tidyr::spread
。尤其dcast.data.table
似乎设置了基调[1],[2],[3],
[4]。这使得基准R中的其他方法reshape
显得过时且几乎无用[5]。
但是,我听说对于reshape
大型数据集(可能是超出RAM的数据集)来说,这仍然是无与伦比的,因为它是唯一可以处理它们的方法,因此它仍然存在。与reshape2::dcast
此相关的崩溃报告支持这一点 [6]。至少有一个参考文献给出了一个暗示,它reshape()
可能确实比reshape2::dcast
真正的“大杂烩” [7]具有优势。
为此寻求证据,我认为值得花时间进行一些研究。所以我做了不同大小的模拟数据的基准,这日益耗尽RAM比较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
Run Code Online (Sandbox Code Playgroud)
RAM大小仅为8 GB,这是我模拟“非常大”数据集的阈值。为了使计算时间合理,我对每种方法仅进行了3次测量,并专注于从长到宽的重塑。
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
Run Code Online (Sandbox Code Playgroud)
(注意:基准测试是在具有Intel Core i5 2.5 GHz,8GB DDR3 RAM 1600 MHz的辅助MacBook Pro上执行的。)
显然,dcast.data.table
似乎总是最快的。不出所料,所有打包方法都无法处理非常大的数据集,这可能是因为计算量超出了RAM内存:
> 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
Run Code Online (Sandbox Code Playgroud)
仅reshape
处理所有数据大小,尽管速度非常慢。
对于小于RAM或其计算不会耗尽RAM的数据集,像dcast
和这样的打包方法spread
非常宝贵。如果数据集大于RAM内存,则打包方法将失败,我们应使用reshape
。
我们能得出这样的结论吗?有人可以澄清一下为什么data.table/reshape
和tidyr
方法失败以及它们的方法学差异是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)
Run Code Online (Sandbox Code Playgroud)
如果您的真实数据与样本数据一样规则,我们可以通过注意到重塑矩阵实际上只是在更改其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
Run Code Online (Sandbox Code Playgroud)
然后在更大的数据上
(对不起,我现在无法承受大量计算)
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
Run Code Online (Sandbox Code Playgroud)
还不错!
关于内存使用情况,reshape
如果您可以使用我的假设或对数据进行预处理以使其符合要求,我想我的解决方案可以解决该问题:
归档时间: |
|
查看次数: |
711 次 |
最近记录: |