wah*_*ulu 25 performance r plyr do.call data.table
我知道在这里有很多关于使用do.call或ldply将data.frames列表转换为单个data.frame的方法,但这个问题是关于理解两种方法的内部工作方式并试图找出原因我无法将两个相同结构,相同字段名称等近100万个df的列表连接到一个data.frame中.每个data.frame都是一行和21列.
数据以JSON文件开头,我使用fromJSON转换为列表,然后运行另一个lapply来提取列表的一部分并转换为data.frame,最后得到一个data.frames列表.
我试过了:
df <- do.call("rbind", list)
df <- ldply(list)
Run Code Online (Sandbox Code Playgroud)
但我不得不在让它运行3个小时并且没有得到任何回报之后终止这个过程.
有更有效的方法吗?我怎样才能解决正在发生的事情以及为什么需要这么长时间?
仅供参考 - 我在使用RHEL的72GB四核服务器上使用RStudio服务器,所以我认为内存不是问题所在.sessionInfo如下:
> sessionInfo()
R version 2.14.1 (2011-12-22)
Platform: x86_64-redhat-linux-gnu (64-bit)
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
[3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=C LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] multicore_0.1-7 plyr_1.7.1 rjson_0.2.6
loaded via a namespace (and not attached):
[1] tools_2.14.1
>
Run Code Online (Sandbox Code Playgroud)
Jos*_*ich 17
rbind.data.frame
做了很多你不需要的检查.如果你只做你想做的事情,这应该是一个非常快速的转变.
# Use data from Josh O'Brien's post.
set.seed(21)
X <- replicate(50000, data.frame(a=rnorm(5), b=1:5), simplify=FALSE)
system.time({
Names <- names(X[[1]]) # Get data.frame names from first list element.
# For each name, extract its values from each data.frame in the list.
# This provides a list with an element for each name.
Xb <- lapply(Names, function(x) unlist(lapply(X, `[[`, x)))
names(Xb) <- Names # Give Xb the correct names.
Xb.df <- as.data.frame(Xb) # Convert Xb to a data.frame.
})
# user system elapsed
# 3.356 0.024 3.388
system.time(X1 <- do.call(rbind, X))
# user system elapsed
# 169.627 6.680 179.675
identical(X1,Xb.df)
# [1] TRUE
Run Code Online (Sandbox Code Playgroud)
受data.table答案的启发,我决定试着让它更快.这是我更新的解决方案,尝试保留复选标记.;-)
# My "rbind list" function
rbl.ju <- function(x) {
u <- unlist(x, recursive=FALSE)
n <- names(u)
un <- unique(n)
l <- lapply(un, function(N) unlist(u[N==n], FALSE, FALSE))
names(l) <- un
d <- as.data.frame(l)
}
# simple wrapper to rbindlist that returns a data.frame
rbl.dt <- function(x) {
as.data.frame(rbindlist(x))
}
library(data.table)
if(packageVersion("data.table") >= '1.8.2') {
system.time(dt <- rbl.dt(X)) # rbindlist only exists in recent versions
}
# user system elapsed
# 0.02 0.00 0.02
system.time(ju <- rbl.ju(X))
# user system elapsed
# 0.05 0.00 0.05
identical(dt,ju)
# [1] TRUE
Run Code Online (Sandbox Code Playgroud)
mne*_*nel 17
鉴于您正在寻找性能,似乎data.table
应该建议一个解决方案.
有一个功能rbindlist
,same
但速度要快得多do.call(rbind, list)
library(data.table)
X <- replicate(50000, data.table(a=rnorm(5), b=1:5), simplify=FALSE)
system.time(rbindlist.data.table <- rbindlist(X))
## user system elapsed
## 0.00 0.01 0.02
Run Code Online (Sandbox Code Playgroud)
它的列表也非常快data.frame
Xdf <- replicate(50000, data.frame(a=rnorm(5), b=1:5), simplify=FALSE)
system.time(rbindlist.data.frame <- rbindlist(Xdf))
## user system elapsed
## 0.03 0.00 0.03
Run Code Online (Sandbox Code Playgroud)
为了比较
system.time(docall <- do.call(rbind, Xdf))
## user system elapsed
## 50.72 9.89 60.88
Run Code Online (Sandbox Code Playgroud)
还有一些适当的基准测试
library(rbenchmark)
benchmark(rbindlist.data.table = rbindlist(X),
rbindlist.data.frame = rbindlist(Xdf),
docall = do.call(rbind, Xdf),
replications = 5)
## test replications elapsed relative user.self sys.self
## 3 docall 5 276.61 3073.444445 264.08 11.4
## 2 rbindlist.data.frame 5 0.11 1.222222 0.11 0.0
## 1 rbindlist.data.table 5 0.09 1.000000 0.09 0.0
Run Code Online (Sandbox Code Playgroud)
benchmark(use.rbl.dt = rbl.dt(X),
use.rbl.ju = rbl.ju (Xdf),
use.rbindlist =rbindlist(X) ,
replications = 5)
## test replications elapsed relative user.self
## 3 use.rbindlist 5 0.10 1.0 0.09
## 1 use.rbl.dt 5 0.10 1.0 0.09
## 2 use.rbl.ju 5 0.33 3.3 0.31
Run Code Online (Sandbox Code Playgroud)
我不确定你真的需要使用as.data.frame
,因为data.table
继承了类data.frame
您观察到所花费的时间随着数据的数量呈指数增长.框架表明将分解rbind
为两个阶段可以加快速度.
这个简单的实验似乎证实了这是一条非常富有成效的道路:
## Make a list of 50,000 data.frames
X <- replicate(50000, data.frame(a=rnorm(5), b=1:5), simplify=FALSE)
## First, rbind together all 50,000 data.frames in a single step
system.time({
X1 <- do.call(rbind, X)
})
# user system elapsed
# 137.08 57.98 200.08
## Doing it in two stages cuts the processing time by >95%
## - In Stage 1, 100 groups of 500 data.frames are rbind'ed together
## - In Stage 2, the resultant 100 data.frames are rbind'ed
system.time({
X2 <- lapply(1:100, function(i) do.call(rbind, X[((i*500)-499):(i*500)]))
X3 <- do.call(rbind, X2)
})
# user system elapsed
# 6.14 0.05 6.21
## Checking that the results are the same
identical(X1, X3)
# [1] TRUE
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3866 次 |
最近记录: |