2012-08-25 16 views
26

Ho un data.table chiamato enc.per.day per gli incontri al giorno. Ha 2403 file in cui è specificata una data di servizio e il numero di pazienti visti in quel giorno. Volevo vedere il numero medio di pazienti visti su qualsiasi tipo di giorno della settimana.Perché la mediana fa scattare dati.table (intero contro doppio)?

enc.per.day[,list(patient.encounters=median(n)),by=list(weekdays(DOS))] 

Quella linea dà un errore

Error in [.data.table (enc.per.day,, la lista (patient.encounters = mediana (n)),: colonne di j non valutano ai tipi coerenti per ciascun gruppo: risultato gruppo 4 presenta colonna 1 tipo 'integer' ma tipo aspetta 'double'

Il seguente tutto lavoro ben

tapply(enc.per.day$n,weekdays(enc.per.day$DOS),median) 
enc.per.day[,list(patient.encounters=round(median(n))),by=list(weekdays(DOS))] 
enc.per.day[,list(patient.encounters=median(n)+0),by=list(weekdays(DOS))] 

Cosa sta succedendo? Mi ci è voluto molto tempo per capire perché il mio codice non funzionasse.

A proposito sottostante vettore enc.per.day $ n è un numero intero

storage.mode(enc.per.day$n) 

restituisce "integer". Inoltre, non ci sono NA da nessuna parte nel data.table.

risposta

37

TL; DR avvolgere median con as.double()

median() 'viaggi up' data.table perché --- anche quando passò solo vettori interi --- median() a volte restituisce un valore intero, e, a volte restituisce un doppio .

## median of 1:3 is 2, of type "integer" 
typeof(median(1:3)) 
# [1] "integer" 

## median of 1:2 is 1.5, of type "double" 
typeof(median(1:2)) 
# [1] "double" 

Riprodurre il messaggio di errore con un esempio minimo:

library(data.table) 
dt <- data.table(patients = c(1:3, 1:2), 
       weekdays = c("Mon", "Mon", "Mon", "Tue", "Tue")) 

dt[,median(patients), by=weekdays] 
# Error in `[.data.table`(dt, , median(patients), by = weekdays) : 
# columns of j don't evaluate to consistent types for each group: 
# result for group 2 has column 1 type 'double' but expecting type 'integer' 

data.table si lamenta perché, dopo aver ispezionato il valore del primo gruppo da elaborare, si è concluso che, OK, questi risultati saranno di tipo "intero". Ma subito dopo (o nel tuo caso nel gruppo 4), viene passato un valore di tipo "double", che non si adatta al suo vettore di risultati "interi".


data.table potrebbe invece accumularsi risultati fino alla fine dei calcoli gruppo-saggio, e quindi eseguire le conversioni di tipo, se necessario, ma ciò richiederebbe un mazzo di overhead performance degradanti; invece, riporta solo ciò che è successo e ti consente di risolvere il problema. Dopo che il primo gruppo è stato eseguito, e conosce il tipo di risultato, alloca un vettore risultato di quel tipo fino al numero di gruppi, quindi lo popola. Se in seguito trova che alcuni gruppi restituiscono più di 1 oggetto, crescerà (cioè rialloca) quel vettore risultante secondo necessità. Nella maggior parte dei casi, tuttavia, la prima ipotesi di data.table per la dimensione finale del risultato è la prima volta corretta (ad esempio, 1 risultato di riga per gruppo) e quindi veloce.

In questo caso, utilizzare as.double(median(X)) anziché median(X) fornisce una soluzione adeguata.

(A proposito, la versione con round() lavorato perché restituisce sempre valori di tipo "doppio", come si può vedere digitando typeof(round(median(1:2))); typeof(round(median(1:3))).)

+1

@ Matteo Dowle - Grazie per l'aggiunta di quei dettagli su come * * data.table ** inizializza e alloca lo spazio per il vettore dei risultati. –

+0

È possibile avere una mediana dello stesso tipo del valore? Perciò anche se avessi valori come = 1,1,1,2,2,2,2 non dovrebbe risultare in mediana = 1,5 invece dovrebbe mostrare mediana = 2. – lony

+0

Come esempio del suggerimento precedente, esegui questo DT [, c (as.double (lapply (.SD, median)), .N), per = x, .SDcols = c ("x", "y "," z ")] anziché DT [, c (lapply (.SD, mediana), .N), da = x, .SDcols = c (" x "," y "," z ")] –

Problemi correlati