2015-11-19 18 views
11

esiste un modo elegante per gestire NA come 0 (na.rm = TRUE) in dplyr?ignora NA in somma riga dplyr

data <- data.frame(a=c(1,2,3,4), b=c(4,NA,5,6), c=c(7,8,9,NA)) 

data %>% mutate(sum = a + b + c) 

a b c sum 
1 4 7 12 
2 NA 8 NA 
3 5 9 17 
4 6 NA NA 

but I like to get 

a b c sum 
1 4 7 12 
2 NA 8 10 
3 5 9 17 
4 6 NA 10 

anche se so che questo non è il risultato desiderato in molti altri casi

risposta

22

si potrebbe usare questo:

library(dplyr) 
data %>% 
    #rowwise will make sure the sum operation will occur on each row 
    rowwise() %>% 
    #then a simple sum(..., na.rm=TRUE) is enough to result in what you need 
    mutate(sum = sum(a,b,c, na.rm=TRUE)) 

uscita:

Source: local data frame [4 x 4] 
Groups: <by row> 

     a  b  c sum 
    (dbl) (dbl) (dbl) (dbl) 
1  1  4  7 12 
2  2 NA  8 10 
3  3  5  9 17 
4  4  6 NA 10 
+0

è meraviglioso! Grazie mille – ckluss

+0

Siete i benvenuti @ckluss. Ho fornito il modo più "dplyr -ico" (se posso dire questo, nel senso che sta usando dplyr in un modo tradizionale come per le esercitazioni) di farlo. Tuttavia, l'uso di altre funzioni di base (da solo o in combinazione con dplyr) è decisamente più efficiente del mio. Le risposte di StevenBeaupre e Akrun sono più efficienti quindi probabilmente staresti meglio con quelle se la velocità è importante per te. – LyzandeR

+0

@LyzandeR Immagino che l'OP abbia voluto il modo 'dplyr'ish. Quindi, non preoccuparti dell'efficienza. – akrun

0

Prova questa

data$sum <- apply(data, 1, sum, na.rm = T) 

risultante data è

a b c sum 
1 1 4 7 12 
2 2 NA 8 10 
3 3 5 9 17 
4 4 6 NA 10 
12

Un'altra opzione:

data %>% 
    mutate(sum = rowSums(., na.rm = TRUE)) 

Benchmark

library(microbenchmark) 
mbm <- microbenchmark(
steven = data %>% mutate(sum = rowSums(., na.rm = TRUE)), 
lyz = data %>% rowwise() %>% mutate(sum = sum(a, b, c, na.rm=TRUE)), 
nar = apply(data, 1, sum, na.rm = TRUE), 
akrun = data %>% mutate_each(funs(replace(., which(is.na(.)), 0))) %>% mutate(sum=a+b+c), 
frank = data %>% mutate(sum = Reduce(function(x,y) x + replace(y, is.na(y), 0), ., 
            init=rep(0, n()))), 
times = 10) 

enter image description here

#Unit: milliseconds 
# expr   min   lq  mean  median   uq  max neval cld 
# steven 9.493812 9.558736 18.31476 10.10280 22.55230 65.15325 10 a 
# lyz 6791.690570 6836.243782 6978.29684 6915.16098 7138.67733 7321.61117 10 c 
# nar 702.537055 723.256808 799.79996 805.71028 849.43815 909.36413 10 b 
# akrun 11.372550 11.388473 28.49560 11.44698 20.21214 155.23165 10 a 
# frank 20.206747 20.695986 32.69899 21.12998 25.11939 118.14779 10 a 
+1

Forse potresti aggiungere akrun? Lo vedo a 1,33 vs il tuo 1.00 in unità = "relativo" (usando questa variazione: 'data%>% mutate (sum = Reduce (funzione (x, y) x + replace (y, is.na (y), 0),., init = rep (0, n())))) – Frank

+1

@Frank Certo, aggiornerò il benchmark. –

5

O replaceNA con 0 e quindi possiamo utilizzare il codice del PO

data %>% 
    mutate_each(funs(replace(., which(is.na(.)), 0))) %>% 
    mutate(Sum= a+b+c) 
    #or as @Frank mentioned 
    #mutate(Sum = Reduce(`+`, .)) 

Sulla base dei parametri di riferimento utilizzando i dati @Steven Beaupré, sembra essere efficace pure.