2014-10-14 20 views
8

che ho fatto una funzione di somma personalizzata che ignora NA s meno che tutti sono NA. Quando lo uso in dplyr restituisce risultati strani e non so perché.funzione di somma personalizzato in dplyr restituisce risultati inconsistenti

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)) 

mi dà

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 

In questo caso è solo sommando su un valore, ma nella mia più grande applicazione in estate forza sui valori multipli. Avvolgere la mia funzione sum0 in as.integer() sembra risolvere il problema, ma non potrei dirti perché.

E 'questo il modo corretto per risolvere questo problema? C'è qualcosa di ovvio che mi manca?

> 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

io non sono sicuro se questo è il modo migliore per scrivere la funzione, ma quella linea è destinata a verificare se tutti i valori sono 'NA's. quindi 'sum0 (c (NA, 3, NA))' restituisce 3, ma 'sum0 (c (NA, NA, NA))' restituisce 'NA'. – Tom

+2

'sum (x, na.rm = ifelse (tutto (is.na (x)), FALSE, TRUE))' lavoro? – rawr

+0

C'è un comportamento leggermente diverso tra 'mean' e' sum' quando si usa 'na.rm = T'. Se tutti sono 'NA',' mean' restituisce 'NaN', mentre' sum' restituisce 0. – Tom

risposta

10

Il problema sembra essere con dplyr determinare il tipo di colonna in riferimento al primo risultato restituito. Se si forza il valore NA, che di default è un valore logico, per essere un NA_real_ o NA_integer_, allora si saranno ordinati:

##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

Grazie @thelatemail che abbia un senso. Quindi normalmente le funzioni restituiscono 'NA' nella" corretta "' classe'? È per questo che questo problema si verifica solo con la mia funzione personalizzata? Ad esempio, noto che 'class (sum (NA))' è 'integer' not' logical'. – Tom

+1

@ Tom - sì, ha a che fare con la gerarchia di diversi tipi di oggetti R. È un po 'confuso, ma forse questa domanda sarà di aiuto: http://stackoverflow.com/questions/21763355/rbind-data-frame-conversion-type-hierarchy-r Penso che questo potrebbe essere 'dplyr' specifico anche se come qualcosa come' class (c (NA, 1)) 'è trattato appropriatamente nella base R. – thelatemail

+2

Per motivi di prestazioni, dplyr assume che i risultati di mutazione siano" tipo stabile "- cioè il tipo del primo elemento è il tipo di tutti gli elementi successivi. Un giorno potremmo essere in grado di rilassare questa restrizione, ma fino ad allora, assicurati che la tua funzione restituisca risultati di un tipo coerente. – hadley

Problemi correlati