【发布时间】:2015-11-29 14:03:09
【问题描述】:
我有一个大型数据集(超过 2000 万个 obs),我使用 survey 包进行分析,运行简单查询需要很长时间。我试图找到一种方法来加速我的代码,但我想知道是否有更好的方法来提高效率。
在我的基准测试中,我使用svyby/svytotal比较了三个命令的速度:
- 简单命令
svyby/svytotal -
foreachdopar7 核并行计算 - 选项 2 的编译版本
剧透:选项 3 的速度是第一个选项的两倍多,但它不适合大型数据集,因为它依赖于并行计算,在处理大型数据时会很快达到内存限制套。尽管我有 16GB 的 RAM,我也面临这个问题。有几个solutions to this memory limitation,但都不适用于勘测设计对象。
关于如何使它更快并且不会因为内存限制而崩溃的任何想法?
我的代码带有可重现的示例:
# Load Packages
library(survey)
library(data.table)
library(compiler)
library(foreach)
library(doParallel)
options(digits=3)
# Load Data
data(api)
# Convert data to data.table format (mostly to increase speed of the process)
apiclus1 <- as.data.table(apiclus1)
# Multiplicate data observations by 1000
apiclus1 <- apiclus1[rep(seq_len(nrow(apiclus1)), 1000), ]
# create a count variable
apiclus1[, Vcount := 1]
# create survey design
dclus1 <- svydesign(id=~dnum, weights=~pw, data=apiclus1, fpc=~fpc)
1) 简单代码
t1 <- Sys.time()
table1 <- svyby(~Vcount,
~stype+dnum+cname,
design = dclus1,
svytotal)
T1 <- Sys.time() - t1
2) 使用 7 核的 foreach dopar 并行计算
# in this option, I create a list with different subsets of the survey design
# that will be passed to different CPU cores to work at the same time
subdesign <- function(i){ subset(dclus1, dnum==i)}
groups <- unique(apiclus1$dnum)
list_subsets <- lapply(groups[], subdesign) # apply function and get all subsets in a list
i <- NULL
# Start Parallel
registerDoParallel(cores=7)
t2 <- Sys.time()
table2 <- foreach (i = list_subsets, .combine= rbind, .packages="survey") %dopar% {
options( survey.lonely.psu = "remove" )
svyby(~Vcount,
~stype+dnum+cname,
design = i,
svytotal)}
T2 <- Sys.time() - t2
3。选项 2 的编译版本
# make a function of the previous query
query2 <- function (list_subsets) { foreach (i = list_subsets, .combine= rbind, .packages="survey") %dopar% {
svyby(~Vcount,
~stype+dnum+cname,
design = i,
svytotal)}}
# Compile the function to increase speed
query3 <- cmpfun(query2 )
t3 <- Sys.time()
table3 <- query3 (list_subsets)
T3 <- Sys.time() - t3
结果
>T1: 1.9 secs
>T2: 1.13 secs
>T3 0.58 secs
barplot(c(T1, T2, T3),
names.arg = c("1) simple table", "2) parallel", "3) compiled parallel"),
ylab="Seconds")
【问题讨论】:
-
请参阅包
ref中的refdata以获取在不为并行处理创建副本的情况下对数据进行子集化的选项。 -
我试过 refdata @A.Webb 但没有用。代码变慢了,它仍然达到内存限制。我可能做错了
groups <- unique(apiclus1$dnum) subdesign <- function(i){ refdata(subset(dclus1, dnum==i))} list_subsets <- lapply(groups[], subdesign) i <- NULL table3 <- foreach (i = 1:length(groups), .combine= rbind, .packages=c("survey","ref")) %dopar% { options( survey.lonely.psu = "remove" ) svyby(~Vcount, ~stype+dnum+cname, design = derefdata(list_subsets[[i]]), svytotal)} -
@RafaelPereira 一起使用
MonetDB.R和survey。例如,请参阅github.com/ajdamico/asdfree/… -
嗨@RafaelPereira,你有没有在这方面取得任何进展?对 4000 万个观测调查数据集 (stackoverflow.com/questions/35210712/…) 有类似问题。尝试实施您描述的“foreach”方法并遇到相同的内存限制问题。
-
嗨@charlie。我还没有找到其他选择。但是,Anthony Damico 在下面提供了一个非常令人满意的答案。
标签: r performance memory survey