2014-10-14 13 views
8

Zrobiłem niestandardową funkcję sumy, która ignoruje NA s, chyba że wszystkie są NA. Kiedy używam go w dplyr, zwraca wyniki nieparzyste i nie wiem dlaczego.Funkcja sumy niestandardowej w dplyr zwraca niespójne wyniki

require(dplyr) 

dta <- data.frame(year=2007:2013, rrconf=c(79, NaN ,474,2792,1686,3313,3456), enrolled=c(NaN,NaN,458,1222,1155,1906,2184)) 

sum0 <- function(x, ...){ 
    # remove NAs unless all are NA 
    if(is.na(mean(x, na.rm=TRUE))) return(NA) 
    else(sum(x, ..., na.rm=TRUE)) 
} 

dta %>% 
    group_by(year) %>% 
    summarize(rrconf=sum0(rrconf), enrolled=sum0(enrolled)) 

daje mi

Source: local data frame [7 x 3] 

    year rrconf enrolled 
1 2007  79  NA 
2 2008  NA  NA 
3 2009 474  TRUE 
4 2010 2792  TRUE 
5 2011 1686  TRUE 
6 2012 3313  TRUE 
7 2013 3456  TRUE 

W tym przypadku jest to podsumowującej tylko na jednej wartości, ale w moim większego zastosowania w lecie może nad wieloma wartościami. Zawijanie mojej funkcji sum0 w as.integer() wydaje się to naprawić, ale nie mogłem ci powiedzieć dlaczego.

Czy to jest właściwy sposób na obejście tego problemu? Czy jest coś oczywistego, czego mi brakuje?

> sessionInfo() 
R version 3.1.0 (2014-04-10) 
Platform: i386-w64-mingw32/i386 (32-bit) 

locale: 
[1] LC_COLLATE=English_United Kingdom.1252 LC_CTYPE=English_United Kingdom.1252 
[3] LC_MONETARY=English_United Kingdom.1252 LC_NUMERIC=C       
[5] LC_TIME=English_United Kingdom.1252  

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

other attached packages: 
[1] dplyr_0.2 

loaded via a namespace (and not attached): 
[1] assertthat_0.1 magrittr_1.0.1 parallel_3.1.0 Rcpp_0.11.2 tools_3.1.0 
+0

Nie jestem pewien, czy jest to najlepszy sposób napisać funkcję, ale linia ta ma na celu sprawdzenie, czy wszystkie wartości są "NA". więc 'sum0 (c (NA, 3, NA))' zwraca 3, ale 'sum0 (c (NA, NA, NA))' zwraca 'NA'. – Tom

+2

'sum (x, na.rm = ifelse (all (is.na (x)), FALSE, TRUE))' działa? – rawr

+0

Istnieje nieco inne zachowanie pomiędzy 'mean' i' sum' przy użyciu 'na.rm = T'. Jeśli wszystkie są "NA", "średnia" zwraca 'NaN', podczas gdy' suma 'zwraca 0. – Tom

Odpowiedz

10

Problem wydaje się być z dplyr określaniem typu kolumny w odniesieniu do pierwszego zwróconego wyniku. Jeśli wymusić wartość NA, który jest domyślnie wartość logiczną, aby być NA_real_ lub NA_integer_, wtedy będą sortowane:

##Just to show what NA normally does first: 
class(NA) 
#[1] "logical" 

sum0 <- function(x, ...){ 
    # remove NAs unless all are NA 
    if(is.na(mean(x, na.rm=TRUE))) return(NA_real_) 
    else(sum(x, ..., na.rm=TRUE)) 
} 

dta %>% 
    group_by(year) %>% 
    summarize(rrconf=sum0(rrconf), enrolled=sum0(enrolled)) 

#Source: local data frame [7 x 3] 
# 
# year rrconf enrolled 
#1 2007  79  NA 
#2 2008  NA  NA 
#3 2009 474  458 
#4 2010 2792  1222 
#5 2011 1686  1155 
#6 2012 3313  1906 
#7 2013 3456  2184 
+0

Dziękuję @ poczta głosowa ma sens. Więc zwykle funkcje zwracające 'NA' robią to w" poprawnej "klasie'? Czy dlatego ten problem występuje tylko w przypadku funkcji niestandardowej? Na przykład zauważam, że 'class (sum (NA))' jest 'liczbą całkowitą', a nie' logiczną'. – Tom

+1

@Tom - tak, ma to związek z hierarchią różnych typów obiektów R. To trochę zagmatwane, ale może to pytanie pomoże: http://stackoverflow.com/questions/21763355/rbind-data-frame-conversion-type-hierarchy-r Myślę, że może to być 'dplyr' specyficzne chociaż jako coś takiego' klasa (c (NA, 1)) 'jest odpowiednio traktowana w bazie R. – thelatemail

+2

Ze względu na wydajność, dplyr zakłada, że ​​wyniki mutacji są" typu stabilnego "- tj. typ pierwszego elementu jest typem wszystkich kolejnych elementów. Pewnego dnia możemy złagodzić to ograniczenie, ale do tego czasu upewnij się, że funkcja zwraca wyniki zgodne z typem. – hadley

Powiązane problemy