2012-08-25 9 views
26

Mam data.table nazwie enc.per.day dla spotkań dziennie. Ma 2403 wierszy, w których określona jest data wykonania usługi i liczba pacjentów widzianych w tym dniu. Chciałem zobaczyć średnią liczbę pacjentów widzianych w każdym dniu tygodnia.Dlaczego mediana potknie się w data.table (integer kontra double)?

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

Linia ta daje błąd

błąd w [.data.table (enc.per.day, wykaz (patient.encounters = mediana (n)),: kolumny J Nie oceniać konsekwentnym typu dla każdej z grup: wynik na 4 grupy jest kolumna 1 typu „całkowita”, ale oczekując typu „podwójny”

Poniżej wszystkie dobrze

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

Co się dzieje? Zajęło mi dużo czasu, aby dowiedzieć się, dlaczego mój kod nie działa.

Nawiasem mówiąc podstawowa wektor enc.per.day $ n jest liczbą całkowitą

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

powraca "całkowitą". Ponadto nie ma żadnych NA w żadnym miejscu w data.table.

Odpowiedz

37

TL; DR owinąć median z as.double()

median() 'podróż górę' data.table ponieważ --- nawet jeśli tylko przekazywane wektorów całkowite --- median() czasami zwraca liczbę całkowitą, a czasami zwraca podwójne .

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

Kopiowanie wiadomość o błędzie przy minimalnym przykład:

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 narzeka, ponieważ po kontroli wartość pierwszej grupy mają być przetwarzane, to stwierdził, że OK, te wyniki będą typu "liczba całkowita". Ale zaraz (lub w twoim przypadku w grupie 4) zostaje przekazana wartość typu "double", która nie pasuje do wektora wyników "integer".


data.table może zamiast tego gromadzą się wyniki do końca obliczeń według grup, a następnie wykonać typu konwersji, jeśli to konieczne, jednak wymaga kilka dodatkowych wydajności degradujący narzut; zamiast tego po prostu zgłasza, co się stało, i pozwala rozwiązać problem. Po uruchomieniu pierwszej grupy i zna typ wyniku, przydziela wektor wyników tego typu tak długo, jak liczba grup, a następnie zapełnia go. Jeśli później okaże się, że niektóre grupy zwracają więcej niż 1 element, to będzie on powiększał (tj. Ponownie przydzielał) wynikowy wektor w razie potrzeby. W większości przypadków jednak domyślne określenie ostatecznego rozmiaru wyniku jest prawidłowe za pierwszym razem (na przykład 1 wynik w wierszu na grupę), a zatem szybko.

W tym przypadku użycie as.double(median(X)) zamiast median(X) zapewnia odpowiednią poprawkę.

(Nawiasem mówiąc, wersja użyciu round() pracował, ponieważ zawsze zwraca wartości typu „double”, jak można zobaczyć wpisując typeof(round(median(1:2))); typeof(round(median(1:3))).)

+1

@Matthew Dowle - Dzięki za dodanie tych szczegółów o tym, jak * * data.table ** inicjuje i przydziela miejsce dla wektora wyników. –

+0

Czy można uzyskać medianę tego samego typu, co wartość? Dlatego nawet jeśli miałbym takie wartości jak = 1,1,1,2,2,2,2, nie powinno to skutkować medianą = 1,5 zamiast tego powinno pokazywać medianę = 2. – lony

+0

Jako przykład powyższej sugestii, wykonaj poniższe DT [, c (as.double (lapply (.SD, median)), .N), by = x, .SDcols = c ("x", "y "," z ")] zamiast DT [, c (lapply (.SD, mediana), .N), przez = x, .SDcols = c (" x "," y "," z ")] –

Powiązane problemy