Coś takiego mnie zaskoczyło: porównajmy dwa sposoby uzyskiwania zmiennych w dużej ramce danych z wieloma kolumnami: rozwiązaniem sapply
i rozwiązaniem pętli for
.Dlaczego przesyłanie zapytań o zmienne w data.frame jest względnie powolne?
bigDF <- as.data.frame(matrix(0, nrow=1E5, ncol=1E3))
library(microbenchmark)
for_soln <- function(x) {
out <- character(ncol(x))
for(i in 1:ncol(x)) {
out[i] <- class(x[,i])
}
return(out)
}
microbenchmark(times=20,
sapply(bigDF, class),
for_soln(bigDF)
)
daje mi na moim komputerze,
Unit: milliseconds
expr min lq median uq max
1 for_soln(bigDF) 21.26563 21.58688 26.03969 163.6544 300.6819
2 sapply(bigDF, class) 385.90406 405.04047 444.69212 471.8829 889.6217
Co ciekawe, jeśli przekształcimy bigDF
do listy sapply
znów jest miły i szybki.
bigList <- as.list(bigDF)
for_soln2 <- function(x) {
out <- character(length(x))
for(i in 1:length(x)) {
out[i] <- class(x[[i]])
}
return(out)
}
microbenchmark(sapply(bigList, class), for_soln2(bigList))
daje mi
Unit: milliseconds
expr min lq median uq max
1 for_soln2(bigList) 1.887353 1.959856 2.010270 2.058968 4.497837
2 sapply(bigList, class) 1.348461 1.386648 1.401706 1.428025 3.825547
Dlaczego są te operacje, zwłaszcza sapply
, biorąc tyle już z data.frame
w porównaniu do list
? I czy istnieje bardziej idiomatyczne rozwiązanie?
pamiętać, że jest wielkość zależny. Na moim komputerze, jeśli zmienię liczbę wierszy na 1000, to 'sapply (bigDF, class)' zajmuje mniej czasu niż 'for_soln (bigDF)'. –