2016-07-23 2 views
0

Je vais juste comprendre un comportement (pour moi) bizarre de la fonction rowSums. Imaginez que j'ai cette dataframe super simple:RowSums NA + NA donne 0

a = c(NA, NA,3) 
b = c(2,NA,2) 
df = data.frame(a,b) 
df 
    a b 
1 NA 2 
2 NA NA 
3 3 2 

et maintenant je veux une troisième colonne qui est la somme des deux autres. Je ne peux pas utiliser simplement+ en raison de la NA:

df$c <- df$a + df$b 
df 
    a b c 
1 NA 2 NA 
2 NA NA NA 
3 3 2 5 

mais si j'utilise rowSums les lignes qui ont NA sont calculées 0, alors que s'il n'y a qu'un tout NA fonctionne très bien:

df$d <- rowSums(df, na.rm=T) 
df 
    a b c d 
1 NA 2 NA 2 
2 NA NA NA 0 
3 3 2 5 10 

Ai-je oublié quelque chose?

Merci à tous

+0

Je me demandais pourquoi personne n'avait répondu 'base :: psum' – rawr

Répondre

6

Une option avec rowSums serait d'obtenir le rowSums avec na.rm=TRUE et multiplier avec le réduit à néant (!) rowSums de niée (!) matrice logique sur la base des valeurs NA après la conversion des lignes qui ont tous dans NA NAs (NA^)

rowSums(df, na.rm=TRUE) *NA^!rowSums(!is.na(df)) 
#[1] 2 NA 10 
+5

Ceci est un hack amusant:' NA^0 == 1'. – lmo

+2

vous devriez ajouter ceci comme réponse à la question liée – rawr

5

Parce que

sum(numeric(0)) 
# 0 

Une fois que vous avez utilisé na.rm = TRUE dans rowSums, la deuxième ligne est numeric(0). Après avoir pris sum, il est 0.

Si vous souhaitez conserver NA pour tous les cas NA, ce serait un travail en deux étapes. Je vous conseille d'écrire une petite fonction à cet effet:

my_rowSums <- function(x) { 
    if (is.data.frame(x)) x <- as.matrix(x) 
    z <- base::rowSums(x, na.rm = TRUE) 
    z[!base::rowSums(!is.na(x))] <- NA 
    z 
    } 

my_rowSums(df) 
# [1] 2 NA 10 

Cela peut être particulièrement utile, si l'entrée est x une trame de données (comme dans votre cas). base::rowSums vérifie d'abord si l'entrée est matricielle ou non. S'il obtient une trame de données, il le convertira en une matrice en premier. La conversion de type est en fait plus coûteuse que le calcul de la somme de lignes réelle. Notez que nous appelons base::rowSums deux fois. Pour réduire le surdébit de conversion de type, nous devons nous assurer que x est une matrice à l'avance.

Pour la réponse "hacking" de @ akrun, je suggère:

akrun_rowSums <- function (x) { 
    if (is.data.frame(x)) x <- as.matrix(x) 
    rowSums(x, na.rm=TRUE) *NA^!rowSums(!is.na(x)) 
    } 

akrun_rowSums(df) 
# [1] 2 NA 10 
+0

mm ok .. Mais que faire si je veux garder NA aussi dans la troisième colonne? – matteo

+4

Ce sera probablement un processus en deux étapes. Par exemple, 'df $ new <- rowSums (df, na.rm = T); is.na (df $ new) <- rowSums (is.na (df)) == longueur (df) ' – lmo