Mam duży zestaw danych (ponad 20 milionów obs.), Który analizuję z pakietem survey
, a przeprowadzenie wyszukiwania prostych zapytań zajmuje mi wiele wieków. Próbowałem znaleźć sposób na przyspieszenie mojego kodu, ale chciałbym wiedzieć, czy istnieją lepsze sposoby na zwiększenie wydajności.Zwiększanie szybkości zapytań przy użyciu złożonego projektu ankiety w R
W moim teście, ja porównać szybkość trzech poleceniach svyby
/svytotal
:
- proste polecenie
svyby
/svytotal
- obliczeń równoległych z
foreach
dopar
użyciu 7 rdzeni - Skompilowany wersją opcji 2
Spoiler: Opcja 3 jest ponad dwukrotnie szybsza niż pierwsza opcja, ALE nie jest odpowiednia dla dużych zestawów danych, ponieważ opiera się na obliczeniach równoległych, które szybko osiągają limity pamięci w przypadku dużych zbiorów danych. Ja też mam ten problem, mimo 16GB pamięci RAM. Jest kilka solutions to this memory limitation, ale żadna z nich nie ma zastosowania do obiektów projektu ankiety.
Jakieś pomysły na to, jak przyspieszyć i nie zawieść z powodu ograniczeń pamięci?
My kod z powtarzalnym np
# 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) prosty kod
t1 <- Sys.time()
table1 <- svyby(~Vcount,
~stype+dnum+cname,
design = dclus1,
svytotal)
T1 <- Sys.time() - t1
2) Obliczenia równoległe z foreach dopar stosując 7 rdzeni
# 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. Skompilowana wersja opcji 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
Wyniki
>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")
Zobacz 'refdata' z pakietu' ref' dla opcji na podzbiór danych bez tworzenia kopii do przetwarzania równoległego. –
Próbowałem już refdata @ A.Webb, ale to nie zadziałało. Kod zwolnił i nadal osiąga limit pamięci. Mogę robić coś złego 'groups <- unique (apiclus1 $ dnum) subdesign <- function (i) {refdata (podzbiór (dclus1, dnum == i))} list_subsets <- lapply (groups [], subdesign) i <- NULL table3 <- foreach (i = 1: długość (grupy), .combine = rbind, .packages = c ("survey", "ref"))% dopar% { opcje (ankieta .lonely.psu = "usunięcie") svyby (~ Vcount, ~ stype + dnum + uÅsÄw, konstrukcja = derefdata (list_subsets [[i]]), svytotal)} ' –
@RafaelPereira użyć' MonetDB.R' i "ankieta" razem. na przykład, zobacz https://github.com/ajdamico/asdfree/search?utf8=%E2%9C%93&q=MonetDB.R –