Nous voulons définir toutes les valeurs d'un tableau zéro qui sont négatives.
J'ai essayé beaucoup de choses mais je n'ai pas encore trouvé de solution de travail. J'ai pensé à une boucle for avec condition, mais cela ne semble pas fonctionner.
#pred_precipitation is our array
pred_precipitation <-rnorm(25,2,4)
for (i in nrow(pred_precipitation))
{
if (pred_precipitation[i]<0) {pred_precipitation[i] = 0}
else{pred_precipitation[i] = pred_precipitation[i]}
}
Merci pour l'exemple reproductible. C'est un truc R assez basique. Vous pouvez attribuer aux éléments sélectionnés d'un vecteur (notez qu'un tableau a des dimensions, et ce que vous avez donné est un vecteur et non un tableau):
> pred_precipitation[pred_precipitation<0] <- 0
> pred_precipitation
[1] 1.2091281 0.0000000 7.7665555 0.0000000 0.0000000 0.0000000 0.5151504 0.0000000 1.8281251
[10] 0.5098688 2.8370263 0.4895606 1.5152191 4.1740177 7.1527742 2.8992215 4.5322934 6.7180530
[19] 0.0000000 1.1914052 3.6152333 0.0000000 0.3778717 0.0000000 1.4940469
Guerres de référence!
@James a trouvé une méthode encore plus rapide et l'a laissée dans un commentaire. Je l'ai voté, ne serait-ce que parce que je sais que sa victoire sera de courte durée.
Tout d'abord, j'essaie de compiler, mais cela ne semble aider personne:
p <- rnorm(10000)
gsk3 <- function(x) { x[x<0] <- 0; x }
jmsigner <- function(x) ifelse(x<0, 0, x)
joshua <- function(x) pmin(x,0)
james <- function(x) (abs(x)+x)/2
library(compiler)
gsk3.c <- cmpfun(gsk3)
jmsigner.c <- cmpfun(jmsigner)
joshua.c <- cmpfun(joshua)
james.c <- cmpfun(james)
microbenchmark(joshua(p),joshua.c(p),gsk3(p),gsk3.c(p),jmsigner(p),james(p),jmsigner.c(p),james.c(p))
expr min lq median uq max
1 gsk3.c(p) 251.782 255.0515 266.8685 269.5205 457.998
2 gsk3(p) 256.262 261.6105 270.7340 281.3560 2940.486
3 james.c(p) 38.418 41.3770 43.3020 45.6160 132.342
4 james(p) 38.934 42.1965 43.5700 47.2085 4524.303
5 jmsigner.c(p) 2047.739 2145.9915 2198.6170 2291.8475 4879.418
6 jmsigner(p) 2047.502 2169.9555 2258.6225 2405.0730 5064.334
7 joshua.c(p) 237.008 244.3570 251.7375 265.2545 376.684
8 joshua(p) 237.545 244.8635 255.1690 271.9910 430.566
Mais attendez! Dirk a écrit ce truc Rcpp. Un incompétent complet en C++ peut-il lire son article JSS, adapter son exemple et écrire la fonction la plus rapide de tous? Restez à l'écoute, chers auditeurs.
library(inline)
cpp_if_src <- '
Rcpp::NumericVector xa(a);
int n_xa = xa.size();
for(int i=0; i < n_xa; i++) {
if(xa[i]<0) xa[i] = 0;
}
return xa;
'
cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")
microbenchmark(joshua(p),joshua.c(p),gsk3(p),gsk3.c(p),jmsigner(p),james(p),jmsigner.c(p),james.c(p), cpp_if(p))
expr min lq median uq max
1 cpp_if(p) 8.233 10.4865 11.6000 12.4090 69.512
2 gsk3(p) 170.572 172.7975 175.0515 182.4035 2515.870
3 james(p) 37.074 39.6955 40.5720 42.1965 2396.758
4 jmsigner(p) 1110.313 1118.9445 1133.4725 1164.2305 65942.680
5 joshua(p) 237.135 240.1655 243.3990 250.3660 2597.429
C'est affirmatif, capitaine.
Cela modifie l'entrée p
même si vous ne l'affectez pas. Si vous voulez éviter ce comportement, vous devez cloner:
cpp_ifclone_src <- '
Rcpp::NumericVector xa(Rcpp::clone(a));
int n_xa = xa.size();
for(int i=0; i < n_xa; i++) {
if(xa[i]<0) xa[i] = 0;
}
return xa;
'
cpp_ifclone <- cxxfunction(signature(a="numeric"), cpp_ifclone_src, plugin="Rcpp")
Ce qui tue malheureusement l'avantage de la vitesse.
J'utiliserais pmax
car ifelse
peut parfois être un peu lent et le remplacement de sous-ensemble crée un vecteur supplémentaire (ce qui peut être un problème avec les grands ensembles de données).
set.seed(21)
pred_precipitation <- rnorm(25,2,4)
p <- pmax(pred_precipitation,0)
Le remplacement de sous-ensemble est de loin le plus rapide:
library(rbenchmark)
gsk3 <- function(x) { x[x<0] <- 0; x }
jmsigner <- function(x) ifelse(x<0, 0, x)
joshua <- function(x) pmin(x,0)
benchmark(joshua(p), gsk3(p), jmsigner(p), replications=10000, order="relative")
test replications elapsed relative user.self sys.self
2 gsk3(p) 10000 0.215 1.000000 0.216 0.000
1 joshua(p) 10000 0.444 2.065116 0.416 0.016
3 jmsigner(p) 10000 0.656 3.051163 0.652 0.000
Alternativement, vous pouvez également utiliser ifelse
:
ifelse(pred_precipitation < 0, 0, pred_precipitation)
Si votre objet principal est un tibble ou un dataframe, vous pouvez également utiliser le package tidy. En comparaison avec le remplacement proposé par Ari B. Friedman, le remplacement pourrait être écrit "à la volée" et combiné avec d'autres mutations.
Un exemple utilisant dplyr et les tuyaux %>%
Ressemblerait à ceci:
df %>% mutate(varA = if_else(varA < 0, 0, varA))
Vous pouvez ajouter d'autres mutations (c'est-à-dire de nouvelles variables) dans l'instruction mutate()
. Un avantage que je vois dans ce type de codage est que vous ne courez pas le risque d'ignorer ou de réexécuter une étape de transformation individuelle, car ils sont tous regroupés dans une seule instruction. Par exemple, en ajoutant %>% View()
dans RStudio, vous pouvez déjà prévisualiser le résultat. Cependant, le résultat n'est encore stocké nulle part ("à la volée"). De cette façon, vous gardez votre espace de noms/environnement propre lors de la modification du code.