3
votes

Moyen efficace de calculer la somme ou de renvoyer NA si toutes les valeurs sont NA

Au cours d'une simulation, j'ai créé plusieurs ensembles de données avec> 1 000 000 de variables. Cependant, certaines des valeurs de ces variables sont NA et dans certains cas, même toutes les valeurs sont NA . Maintenant, j'aimerais calculer la somme de toutes les valeurs des variables, mais je veux obtenir NA si toutes les valeurs sont NA .

Le problème avec le sum (x, na.rm = T) ou sum (na.omit (x)) est, qu'il renvoie 0 si toutes les valeurs sont NA . Ainsi, j'ai écrit ma propre fonction qui traite NA de la manière attendue:

sumna <- function(x) {
  sumna <- NULL
  return(ifelse(all(is.na(x)), NA, sum(na.omit(x))))
}

Cependant, cette implémentation est plutôt lente. p>

Ainsi, je recherche une implémentation ou une fonction pré-implémentée qui résume les valeurs d'un vecteur, omet NA et renvoie NA si toutes les valeurs sont NA.

Merci d'avance!

r sum na

1 commentaires

Pouvez-vous expliquer ce que vous entendez par «plutôt lent»? Il faut environ 5 à 10 fois plus de temps pour générer un million d'écarts aléatoires x <- rnorm (1000000) que pour appliquer sumna (x) et sumna ( x) prend quelques millisecondes, donc je suppose que la plupart de votre temps de calcul est dans les simulations plutôt que dans cette étape?


5 Réponses :


7
votes


2 commentaires

Merci beaucoup, je pense que c'est exactement ce dont j'ai besoin!


sum_ est lent? x = rnorm (1000000); microbenchmark (sumna (x), sum_ (x)) pour votre sumna () ?



2
votes

Vous pouvez utiliser colSums . En supposant que vous n'ayez pas de colonne avec tous les 0,

ifelse(colSums(abs(df), na.rm = TRUE) == 0, NA, colSums(df, na.rm = TRUE))


1 commentaires

Pourrait fonctionner. Mais dans le cas où certaines des valeurs numériques s'ajouteraient à 0, j'aurais des doutes sur l'utilisation.



3
votes

Vous pouvez également sous-définir des valeurs en fonction du nombre de NA dans x

sumna <- function(x) {
   c(NA, sum(x, na.rm = TRUE))[(sum(is.na(x)) != length(x)) +1]
}

sumna(c(1:10, NA))
#[1] 55
sumna(c(NA, NA, NA))
#[1] NA
sumna(1:5)
#[1] 15


0 commentaires

4
votes

Vous pouvez supprimer tous les NA et tester si la longueur est supérieure à 0.

sumna_c <- function(x) {
    ret <- sum(x, na.rm = TRUE)
    if(ret == 0 && all(is.na(x))) {NA} else {ret}
}

Je pense que dans la plupart des cas, cela devrait être efficace si vous utilisez simplement sum (x, na .rm = TRUE) et testez ensuite quand sum == 0 s'il n'y a que NA comme:

sumna_a <- function(x) {
    x <- na.omit(x)
    if(length(x)) return(sum(x))
    NA
}

#or
sumna_b <- function(x) {
    if(length(na.omit(x))) return(sum(x, na.rm = TRUE))
    NA
}


4 commentaires

Ce n'est pas une réponse, veuillez faire de cet article un article wiki .


il est plus rapide d'utiliser x [! is.na (x)] pour des vecteurs simples, plutôt que na.omit () .


@MartinMorgan Sur mon PC et ma version R na.omit () est plus rapide que x [! Is.na (x)]


Ah; essayez y = rep (NA_real_, 1000000) . De plus, je ne suis pas sûr de la question initiale de savoir si le problème concerne un million de variables ou un million de simulations pour chacune de quelques variables.



4
votes

En comparant les méthodes publiées, il semble que la fonction user10488504 c est actuellement la plus performante pour les cas où votre somme est! = 0 et vous n'avez pas que des NA. Si vous n'avez que l ' Anti de NA, RonakShah et akrun sont bons:

sumna_Anti <- function(x) {
  sumna <- NULL
  return(ifelse(all(is.na(x)), NA, sum(na.omit(x))))
}

sumna_RonakShah <- function(x) {
   c(NA, sum(x, na.rm = TRUE))[(sum(is.na(x)) != length(x)) +1]
}

sumna_akrun <- function(x) {
       if(all(is.na(x))) NA else sum(x, na.rm = TRUE)
   }

sumna_user10488504_a <- function(x) {
    x <- na.omit(x)
    if(length(x)) return(sum(x))
    NA
}

sumna_user10488504_b <- function(x) {
    if(length(na.omit(x))) return(sum(x, na.rm = TRUE))
    NA
}

sumna_user10488504_c <- function(x) {
    ret <- sum(x, na.rm = TRUE)
    if(ret == 0 && all(is.na(x))) {NA} else {ret}
}

set.seed(0)
x <- rnorm(99999)

library(microbenchmark)
microbenchmark(sumna_Anti(x),
               sumna_RonakShah(x),
               sumna_akrun(x),
               sumna_user10488504_a(x),
               sumna_user10488504_b(x),
               sumna_user10488504_c(x)
               )

                    expr     min       lq      mean   median       uq      max neval  cld
           sumna_Anti(x) 307.288 310.0280 390.01838 319.2800 410.2040 2056.284   100    d
      sumna_RonakShah(x) 245.251 247.4715 269.40054 253.1650 259.7850  393.495   100  bc 
          sumna_akrun(x) 165.998 167.5005 209.39315 171.8925 190.8330 1768.761   100  b  
 sumna_user10488504_a(x) 221.275 222.6740 315.93037 229.0330 263.6405 1944.602   100   cd
 sumna_user10488504_b(x) 224.614 225.8170 261.77913 231.2305 234.6465 1934.120   100  bc 
 sumna_user10488504_c(x)  83.367  84.2610  86.16793  84.5900  86.4585  119.629   100 a   


x[sample(1:99999, 100)] <- NA
microbenchmark(sumna_Anti(x),
               sumna_RonakShah(x),
               sumna_akrun(x),
               sumna_user10488504_a(x),
               sumna_user10488504_b(x),
               sumna_user10488504_c(x)
               )

                    expr     min       lq      mean   median        uq      max neval  cld
           sumna_Anti(x) 607.367 628.4000 907.53974 634.3195  692.0845 4205.011   100    d
      sumna_RonakShah(x) 246.992 251.1290 273.80595 254.6195  261.4470  455.446   100  b  
          sumna_akrun(x) 167.058 168.5790 196.13280 170.4125  186.2650  373.708   100 ab  
 sumna_user10488504_a(x) 517.615 539.2940 684.20267 543.6295  582.5330 2360.247   100   c 
 sumna_user10488504_b(x) 523.769 544.6195 869.76645 558.0240 1125.6725 3914.266   100    d
 sumna_user10488504_c(x)  84.142  85.2940  89.04266  86.4255   87.4020  207.624   100 a   

x = rep(NA_real_, 99999)
microbenchmark(sumna_Anti(x),
               sumna_RonakShah(x),
               sumna_akrun(x),
               sumna_user10488504_a(x),
               sumna_user10488504_b(x),
               sumna_user10488504_c(x)
               )

           sumna_Anti(x)  243.848  252.3825  308.2693  260.5285  286.8025  2198.275   100  a 
      sumna_RonakShah(x)  242.706  249.3855  287.1426  258.8390  278.5905  1882.114   100  a 
          sumna_akrun(x)  240.459  244.9125  269.2847  255.1230  274.9215   409.886   100  a 
 sumna_user10488504_a(x) 1241.069 1285.3075 1534.1261 1343.7185 1486.4220  3117.453   100  ab
 sumna_user10488504_b(x) 1244.580 1281.9825 2461.2302 1349.9840 1427.9640 97590.279   100   b
 sumna_user10488504_c(x)  320.084  323.1905  353.9885  340.3555  358.7490   478.537   100  a 


0 commentaires