2014-08-29 12 views
17

Rozważmy następujący wektor nazwany x.Obliczenie sumy kumulacji() podczas ignorowania wartości NA

(x <- setNames(c(1, 2, 0, NA, 4, NA, NA, 6), letters[1:8])) 
# a b c d e f g h 
# 1 2 0 NA 4 NA NA 6 

Chciałbym obliczyć skumulowana suma x ignorując wartości NA. Ponieważ nie ma argumentu na.rm dla cumsum(), jest to nieco trudne.

Mogę to zrobić w ten sposób.

y <- setNames(numeric(length(x)), names(x)) 
z <- cumsum(na.omit(x)) 
y[names(y) %in% names(z)] <- z 
y[!names(y) %in% names(z)] <- x[is.na(x)] 
y 
# a b c d e f g h 
# 1 3 3 NA 7 NA NA 13 

Ale wydaje się to przesadne i powoduje wiele nowych przydziałów/kopii. Jestem pewien, że jest lepszy sposób.

Co lepsze metody są tam wrócić skumulowaną sumę natomiast skutecznie ignorującNAwartości?

Odpowiedz

12

Chcesz coś takiego:

x2 <- x 
x2[!is.na(x)] <- cumsum(x2[!is.na(x)]) 

x2 

[edytuj] Alternatywnie, jak sugeruje komentarzu powyżej, można zmienić NA do 0'S -

miss <- is.na(x) 
x[miss] <- 0 
cs <- cumsum(x) 
cs[miss] <- NA 
# cs is the requested cumsum 
+0

One-liner robi to samo: '" [<- "(x,! Is.na (x), cumsum (na.omit (x)))' – lebatsnok

+1

Nie jest bardziej czytelną wersją tego samego rzecz 'x [! is.na (x)] <- cumsum (na.omit (x))'? –

+2

Jest bardziej czytelny, ale to nie to samo. '" [<- "(x, bla ...' robi to, co OP zapytał * bez zmiany x *, twoja wersja przypisuje podzbiór na x i zwraca 'cumsum (na.omit (x))'. Więc to zdecydowanie nie to samo - Bardziej czytelna wersja jednolinijnego, robiącego to samo, byłaby to: 'replace (x,! is.na (x), cumsum (na.omit (x)))' – lebatsnok

21

Można to zrobić w jedna linia z:

cumsum(ifelse(is.na(x), 0, x)) + x*0 
# a b c d e f g h 
# 1 3 3 NA 7 NA NA 13 
6

Oto funkcja, którą wymyśliłem z odpowiedzi na to pytanie. Pomyślałem, że podzielę się tym, ponieważ wydaje się, że działa dobrze. Oblicza on skumulowany FUNC z x, ignorując NA. FUNC może być jednym z następujących: sum(), prod(), min() lub max(), a x jest wektorem numerycznym.

cumSkipNA <- function(x, FUNC) 
{ 
    d <- deparse(substitute(FUNC)) 
    funs <- c("max", "min", "prod", "sum") 
    stopifnot(is.vector(x), is.numeric(x), d %in% funs) 
    FUNC <- match.fun(paste0("cum", d)) 
    x[!is.na(x)] <- FUNC(x[!is.na(x)]) 
    x 
} 

set.seed(1) 
x <- sample(15, 10, TRUE) 
x[c(2,7,5)] <- NA 
x 
# [1] 4 NA 9 14 NA 14 NA 10 10 1 
cumSkipNA(x, sum) 
# [1] 4 NA 13 27 NA 41 NA 51 61 62 
cumSkipNA(x, prod) 
# [1]  4  NA  36 504  NA 7056  NA 
# [8] 70560 705600 705600 
cumSkipNA(x, min) 
# [1] 4 NA 4 4 NA 4 NA 4 4 1 
cumSkipNA(x, max) 
# [1] 4 NA 9 14 NA 14 NA 14 14 14 

Zdecydowanie nic nowego, ale może być przydatne dla kogoś.

+1

it's bardzo przydatna funkcja ogólnego zastosowania - świetna – jalapic

Powiązane problemy