La Performance de rbind.les données.cadre
-
12-11-2019 - |
Question
J'ai une liste de dataframes pour laquelle je suis certain qu'ils contiennent tous au moins une ligne (en fait, certains contiennent qu'une seule ligne, et d'autres contiennent un nombre donné de lignes), et qu'ils ont tous les mêmes colonnes (noms et types).En cas de questions, je suis également certain qu'il n'y a pas de NA n'importe où dans les lignes.
La situation peut être simulé comme ceci:
#create one row
onerowdfr<-do.call(data.frame, c(list(), rnorm(100) , lapply(sample(letters[1:2], 100, replace=TRUE), function(x){factor(x, levels=letters[1:2])})))
colnames(onerowdfr)<-c(paste("cnt", 1:100, sep=""), paste("cat", 1:100, sep=""))
#reuse it in a list
someParts<-lapply(rbinom(200, 1, 14/200)*6+1, function(reps){onerowdfr[rep(1, reps),]})
J'ai mis les paramètres (de la randomisation), de sorte qu'ils approximative ma véritable situation.
Maintenant, je veux réunir tous ces dataframes dans un dataframe.J'ai pensé à l'aide de rbind ferait l'affaire, comme ceci:
system.time(
result<-do.call(rbind, someParts)
)
Maintenant, sur mon système (qui n'est pas particulièrement lent), et avec les paramètres ci-dessus, c'est la sortie du système.temps:
user system elapsed
5.61 0.00 5.62
Près de 6 secondes pour rbind-ing 254 (dans mon cas) les lignes de 200 variables?Sûrement, il y a un moyen d'améliorer la performance ici?Dans mon code, je dois faire des choses similaires très souvent (c'est à partir de l'imputation multiple), donc j'ai besoin de cela pour être aussi rapide que possible.
La solution
Pouvez-vous construire votre matrices avec des variables numériques uniquement et convertir à un facteur à la fin? rbind
est beaucoup plus rapide sur les numériques des matrices.
Sur mon système, à l'aide de trames de données:
> system.time(result<-do.call(rbind, someParts))
user system elapsed
2.628 0.000 2.636
La construction de la liste avec tous numériques des matrices à la place:
onerowdfr2 <- matrix(as.numeric(onerowdfr), nrow=1)
someParts2<-lapply(rbinom(200, 1, 14/200)*6+1,
function(reps){onerowdfr2[rep(1, reps),]})
résultats dans beaucoup plus vite rbind
.
> system.time(result2<-do.call(rbind, someParts2))
user system elapsed
0.001 0.000 0.001
EDIT:Voici une autre possibilité;il combine chaque colonne à son tour.
> system.time({
+ n <- 1:ncol(someParts[[1]])
+ names(n) <- names(someParts[[1]])
+ result <- as.data.frame(lapply(n, function(i)
+ unlist(lapply(someParts, `[[`, i))))
+ })
user system elapsed
0.810 0.000 0.813
Toujours pas presque aussi rapidement qu'à l'aide de matrices si.
EDIT 2:
Si vous n'avez que des nombres et des facteurs, il n'est pas difficile de convertir tout numérique, rbind
eux, et de convertir les colonnes nécessaires arrière de facteurs.Cela suppose que tous les facteurs ont exactement les mêmes niveaux.La conversion d'un facteur par rapport à un nombre entier est également plus rapide que du numérique donc je me force à l'entier en premier.
someParts2 <- lapply(someParts, function(x)
matrix(unlist(x), ncol=ncol(x)))
result<-as.data.frame(do.call(rbind, someParts2))
a <- someParts[[1]]
f <- which(sapply(a, class)=="factor")
for(i in f) {
lev <- levels(a[[i]])
result[[i]] <- factor(as.integer(result[[i]]), levels=seq_along(lev), labels=lev)
}
La synchronisation de mon système:
user system elapsed
0.090 0.00 0.091
Autres conseils
Not a huge boost, but swapping rbind
for rbind.fill
from the plyr
package knocks about 10% off the running time (with the sample dataset, on my machine).
If you really want to manipulate your data.frame
s faster, I would suggest to use the package data.table
and the function rbindlist()
. I did not perform extensive tests but for my dataset (3000 dataframes, 1000 rows x 40 columns each) rbindlist()
takes only 20 seconds.
This is ~25% faster, but there has to be a better way...
system.time({
N <- do.call(sum, lapply(someParts, nrow))
SP <- as.data.frame(lapply(someParts[[1]], function(x) rep(x,N)))
k <- 0
for(i in 1:length(someParts)) {
j <- k+1
k <- k + nrow(someParts[[i]])
SP[j:k,] <- someParts[[i]]
}
})
Make sure you're binding dataframe to dataframe. Ran into huge perf degradation when binding list to dataframe.