szukam korzystać data.table
celu zwiększenia szybkości dla danej funkcji, ale nie jestem pewien, że jestem jej wdrażania prawidłowy sposób:r - zastosować funkcję do każdego wiersza z data.table
dane
podawana dwa data.table
s (dt
i dt_lookup
)
library(data.table)
set.seed(1234)
t <- seq(1,100); l <- letters; la <- letters[1:13]; lb <- letters[14:26]
n <- 10000
dt <- data.table(id=seq(1:n),
thisTime=sample(t, n, replace=TRUE),
thisLocation=sample(la,n,replace=TRUE),
finalLocation=sample(lb,n,replace=TRUE))
setkey(dt, thisLocation)
set.seed(4321)
dt_lookup <- data.table(lkpId = paste0("l-",seq(1,1000)),
lkpTime=sample(t, 10000, replace=TRUE),
lkpLocation=sample(l, 10000, replace=TRUE))
## NOTE: lkpId is purposly recycled
setkey(dt_lookup, lkpLocation)
mam funkcji znajdująca lkpId
zawierający zarówno thisLocation
i finalLocation
i ma "najbliższy" lkpTime
(tj. minimalna nieujemną wartość thisTime - lkpTime
)
Funkcja
## function to get the 'next' lkpId (i.e. the lkpId with both thisLocation and finalLocation,
## with the minimum non-negative time between thisTime and dt_lookup$lkpTime)
getId <- function(thisTime, thisLocation, finalLocation){
## filter lookup based on thisLocation and finalLocation,
## and only return values where the lkpId has both 'this' and 'final' locations
tempThis <- unique(dt_lookup[lkpLocation == thisLocation,lkpId])
tempFinal <- unique(dt_lookup[lkpLocation == finalLocation,lkpId])
availServices <- tempThis[tempThis %in% tempFinal]
tempThisFinal <- dt_lookup[lkpId %in% availServices & lkpLocation==thisLocation, .(lkpId, lkpTime)]
## calcualte time difference between 'thisTime' and 'lkpTime' (from thisLocation)
temp2 <- thisTime - tempThisFinal$lkpTime
## take the lkpId with the minimum non-negative difference
selectedId <- tempThisFinal[min(which(temp2==min(temp2[temp2>0]))),lkpId]
selectedId
}
Próby rozwiązania
trzeba uzyskać lkpId
dla każdego rzędu dt
. Dlatego moim początkowym instynktem było użycie funkcji *apply
, ale trwało to zbyt długo (dla mnie), gdy n/nrow > 1,000,000
. Więc starałem się wdrożyć rozwiązanie data.table
, aby zobaczyć, czy to szybciej:
selectedId <- dt[,.(lkpId = getId(thisTime, thisLocation, finalLocation)),by=id]
Jednak jestem dość nowy data.table
, a metoda ta wydaje się nie dawać żadnych wzrost wydajności ponad roztworze *apply
:
lkpIds <- apply(dt, 1, function(x){
thisLocation <- as.character(x[["thisLocation"]])
finalLocation <- as.character(x[["finalLocation"]])
thisTime <- as.numeric(x[["thisTime"]])
myId <- getId(thisTime, thisLocation, finalLocation)
})
oba trwają ~ 30 sekund dla n = 10 000.
Pytanie
Czy istnieje lepszy sposób korzystania data.table
zastosować funkcję getId
nad każdym rzędzie dt
?
Aktualizuj 12/08/2015
Dzięki wskaźnik z @eddi Mam przebudowany całe algorytm i robię zastosowanie skręcania przyłącza (a good introduction), a tym samym właściwego stosowania data.table
. Napiszę później odpowiedź.
radziłbym, aby zminimalizować przykładowe dane, jeśli uda się pokazać problem na 10-20 wierszy dostaniesz dużo więcej użytkownikowi w stanie zbadać problem.Dodatkowo twoje obecne rozwiązania powodują wielokrotne ostrzeżenia na mojej maszynie. Mając małe przykładowe dane, możesz również opublikować oczekiwany wynik. – jangorecki
@jangorecki Moje pytania nie dotyczą problemu z kodem lub funkcją * per se *, to pytanie, czy istnieje lepszy sposób użycia 'data.table' na dużym zestawie danych. W tym przykładzie ostrzeżenia mogą być po prostu ignorowane (są tam, gdzie funkcja nie może znaleźć odpowiedzi - co jest ok). – tospig
'data.table' nie przyspieszy w magiczny sposób tej samej pętli. Powinieneś przemyśleć swój algorytm - najłatwiej znaleźć najbliższy czas za pomocą ruchomych połączeń, ale nie jestem pewien, co zrobić z początkową operacją "filtru". – eddi