J'apprends des méthodes pour améliorer la performance d'un code. Pour l'étude que j'ai écrit la fonction qui retourne la statistique descriptive de base comme psych::describe
. J'ai essayé différentes versions des boucles et pour le moment c'est tout ce que je pouvais faire.Améliorer la fonction de performance
code:
x <- matrix(rnorm(10*100), nrow=100) # sample data for tests
descStats <- function(x, na.rm = TRUE, trim = NULL, skew = FALSE, byrow = FALSE, digits = getOption("digits")) {
if (!is.matrix(x)) x <- as.matrix(x)
if(byrow) x <- t(x)
stats <- c("n", "mean", "se", "sd", "median", "min", "max", "range") # descriptive statistics
if (skew) {
library(moments)
stats <- c(stats, "skewness", "kurtosis")
}
if (!is.null(trim)) {
stats <- append(stats, "trimmed", which(stats == "mean"))
trimmed <- function(x) base::mean(x, trim=trim)
}
n <- function(x) length(x)
range <- function(x) max(x) - min(x)
mean <- function(x) .Internal(mean(x)) # redefined mean function
sd <- function(x) sqrt(sum((x - mean(x))^2)/(length(x)-1)) # redefined sd function
se <- function(x) sqrt(sd(x)/length(x))
median <- function(x) { # redefined median function
n <- length(x)
half <- (n + 1L)%/%2L
if (n%%2L == 1L)
result <- .Internal(sort(x, partial = half))[half]
else {
result <- mean(.Internal(sort(x, partial = half + 0L:1L))[half + 0L:1L])
}
}
describe <- function(x, na.rm=FALSE) {
if (na.rm) x <- x[!is.na(x)]
result <- vapply(stats, function(fun) eval(call(fun, x)), FUN.VALUE=numeric(1))
return(result)
}
out <- t(vapply(seq_len(ncol(x)), function(i) describe(x[,i], na.rm=na.rm), FUN.VALUE=numeric(length(stats))))
out <- round(out, digits=digits)
return(out)
}
print(descStats(x))
## n mean trimmed se sd median min max range
## [1,] 100 0.2524298 0.2763559 0.1024722 1.0500560 0.2842625 -2.905826 3.362598 6.268424
## [2,] 100 -0.1201740 -0.0627668 0.1027268 1.0552801 -0.0614541 -3.071836 2.247063 5.318899
## [3,] 100 0.2074781 0.1946393 0.1006384 1.0128089 0.1928790 -2.312749 2.564297 4.877047
## [4,] 100 0.1088077 0.1127540 0.0935370 0.8749172 0.0864728 -2.757226 2.883687 5.640913
## [5,] 100 -0.2163515 -0.2147170 0.1064167 1.1324524 -0.2836884 -3.431254 2.950466 6.381720
## [6,] 100 -0.0324696 -0.0229878 0.0968330 0.9376630 0.0919468 -2.474992 1.860961 4.335953
## [7,] 100 -0.1497724 -0.1665687 0.1047835 1.0979579 -0.1753578 -2.908781 2.885645 5.794425
## [8,] 100 -0.0197306 0.0101194 0.1030385 1.0616927 0.0615438 -2.711356 2.506423 5.217779
## [9,] 100 -0.0346922 -0.0290022 0.1018726 1.0378033 0.0231049 -2.467852 2.528595 4.996447
## [10,] 100 0.1251403 0.1222156 0.1012441 1.0250359 0.1606492 -2.566209 2.854519 5.420728
Dans chaque cas, je compare le temps écoulé avec microbenchmaark
. Par exemple:
library(microbenchmark)
bench <- microbenchmark(descStats(x), descStats2(x), times=1000)
print(bench)
boxplot(bench, outline=FALSE)
Quelqu'un peut-il être en mesure d'offrir une version plus efficace ou plus compacte du code?
Mise à jour:
La version finale de cette fonction vous pouvez voir here.
J'ai essayé 'Rprof'. J'ai changé 'eval (call)' en 'get' mais cela a conduit à une augmentation du temps écoulé. 'sort.int 'utilisé par' mean.default' et 'median.default'. –
Ajouter 'sd <- fonction (x) sqrt (somme ((x - mean (x))^2)/(longueur (x) -1))' conduit à réduire le temps écoulé de ~ 25%. –
Également amélioré 'median'. Je copie une partie du code 'median' d'origine et remplace l'appel' mean' et 'sort' par' .Internal'. –