2013-09-26 27 views
9

mi podział ramki danych z split() w celu wykorzystania parLapply() do wywoływania funkcji każdej partycji równolegle. Ramka danych ma 1,3 miliona wierszy i 20 koli. Dzielę się/dzielę na dwie kolumny, oba typy znaków. Wygląda na to, że są to unikalne identyfikatory ~ 47K i unikalne kody ~ 12K, ale nie wszystkie pary identyfikatorów i kodów są dopasowane. Wynikowa liczba partycji wynosi ~ 250 KB. Oto split() linia:szybki sposób rozdzielić w R

system.time(pop_part <- split(pop, list(pop$ID, pop$code))) 

Przegrody zostaną następnie podawany do parLapply() następująco:

cl <- makeCluster(detectCores()) 
system.time(par_pop <- parLapply(cl, pop_part, func)) 
stopCluster(cl) 

Mam niech sam kod split() uruchomić prawie godzinę i to nie kompletne. Mogę się podzielić przez sam identyfikator, co zajmuje około 10 minut. Dodatkowo, studio R i wątki robocze zużywają ~ 6 GB pamięci RAM.

Powód, dla którego znam wynikową liczbę partycji, mam równoważny kod w Pentaho Data Integration (PDI), który działa w ciągu 30 sekund (dla całego programu, a nie tylko "podzielony" kod). Nie mam nadziei na tego rodzaju występy z R, ale coś, co może zakończyć się w najgorszym przypadku w 10-15 minut.

Główne pytanie: Czy istnieje lepsza alternatywa dla podziału? Próbowałem też ddply() z .parallel = TRUE, ale trwało to ponad godzinę i nigdy się nie zakończyło.

Odpowiedz

9

dzielona indeksy język pop

idx <- split(seq_len(nrow(pop)), list(pop$ID, pop$code)) 

Splicie nie jest powolny, np

> system.time(split(seq_len(1300000), sample(250000, 1300000, TRUE))) 
    user system elapsed 
    1.056 0.000 1.058 

więc jeśli twój jest Chyba istnieje jakiś aspekt swojej danych, które spowalnia rzeczy w dół, np ID i code są czynnikami o wielu poziomach, więc ich całkowita interakcja, a nie kombinacje poziomów pojawiające się w zbiorze danych, są obliczane:

> length(split(1:10, list(factor(1:10), factor(10:1)))) 
[1] 100 
> length(split(1:10, paste(letters[1:10], letters[1:10], sep="-"))) 
[1] 10 

czy może jesteś na wyczerpaniu pamięci.

Użyj mclapply zamiast parLapply, jeśli używasz procesów na komputerze innym niż system Windows (co prawdopodobnie jest, ponieważ pytasz o numer detectCores()).

par_pop <- mclapply(idx, function(i, pop, fun) fun(pop[i,]), pop, func) 

Koncepcyjnie to brzmi jakbyś naprawdę dąży do pvec (rozprowadzać Vectorized obliczenie nad procesorów) zamiast mclapply (iteracyjne nad poszczególnymi rzędami w ramce danych).

Również i naprawdę jako pierwszy krok, należy rozważyć identyfikacji szyjek butelek w func; dane są duże, ale nie tak duże, więc być może równoległa ocena nie jest potrzebna - może napisałeś kod PDI zamiast kodu R? Zwróć uwagę na typy danych w ramce danych, np. Czynnik kontra znak. Nie jest niczym niezwykłym uzyskanie 100-krotnego przyspieszenia między słabo napisanym i wydajnym kodem R, podczas gdy równoległa ocena jest w najlepszym razie proporcjonalna do liczby rdzeni.

+0

Dzięki, spróbuję. Ha, faktycznie napisałem kod R początkowo, a następnie przeniesiłem go do PDI (jestem bardziej doświadczony z R niż PDI). – argoneus

+0

Uruchomiłem kod 'split()', który wysłałeś i czekałeś przez prawie godzinę, ale nigdy nie został on ukończony. – argoneus

+0

Dodano kilka dodatkowych sugestii dotyczących podziału, które powinny trwać co najmniej sekundę. Może czynniki powodują również, że func jest wolny? –

2

Split (x, f) jest powolny, jeśli x jest czynnikiem i F zawiera wiele różnych elementów

Tak, ten kod jeśli szybko:

system.time(split(seq_len(1300000), sample(250000, 1300000, TRUE))) 

Ale to jest bardzo powolny:

system.time(split(factor(seq_len(1300000)), sample(250000, 1300000, TRUE))) 

I to szybko ponownie, ponieważ istnieje tylko 25 grup

system.time(split(factor(seq_len(1300000)), sample(25, 1300000, TRUE)))