2013-09-26 4 views
9

Я разбиваю фрейм данных на split(), чтобы использовать функцию parLapply() для вызова функции на каждом разделе параллельно. Кадр данных имеет 1,3 миллиона строк и 20 столбцов. Я разбиваю/разбиваю на два столбца, оба типа символа. Похоже, есть уникальные коды ~ 47K и уникальные коды ~ 12K, но не все пары идентификаторов и кода совпадают. Итоговое число разделов составляет ~ 250K. Вот split() линия:Быстрая альтернатива расколу в R

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

Перегородки будет подаваться в parLapply() следующим образом:

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

Я пусть split() код в одиночку работать почти час, и это не полный. Я могу разделить только ID, что занимает ~ 10 минут. Кроме того, студия R и рабочие потоки потребляют ~ 6 ГБ оперативной памяти.

Причина, по которой я знаю результирующее количество разделов, - это эквивалентный код в интеграции данных Pentaho (PDI), который запускается через 30 секунд (для всей программы, а не только для «разделенного» кода). Я не надеюсь на этот тип производительности с R, но что-то, что, возможно, завершается в 10-15 минут в худшем случае.

Главный вопрос: есть ли лучшая альтернатива расколу? Я также пробовал ddply() с .parallel = TRUE, но он также прослужил более часа и никогда не заканчивался.

ответ

9

Сплит индексы в pop

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

Сплит не медленно, например,

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

так, если у вас, я думаю, есть некоторые аспекты ваших данных, что замедляет работу, например, ID и code - оба фактора со многими уровнями и поэтому рассчитывается их полное взаимодействие, а не комбинации уровней, отображаемые в вашем наборе данных.

> 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 

или, возможно, у вас заканчивается память.

Используйте mclapply, а не parLapply, если вы используете процессы на машине, отличной от Windows (что, я думаю, это так, так как вы запрашиваете detectCores()).

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

Концептуально это звучит, как вы действительно стремитесь к pvec (распространять векторизованное вычисление над процессорами), а не mclapply (итерация по отдельным строкам в кадре данных).

Кроме того, и в качестве первоначального шага рассмотрите определение шеек бутылок в func; данные большие, но не такие большие, поэтому, возможно, параллельная оценка не нужна - возможно, вы написали код PDI вместо R-кода? Обратите внимание на типы данных в кадре данных, например, фактор против характера. Нет ничего необычного в том, чтобы получить 100-кратное ускорение между плохо написанным и эффективным R-кодом, тогда как параллельная оценка в лучшем случае пропорциональна количеству ядер.

+0

Спасибо, я попробую. Ха, я на самом деле написал R-код изначально, а затем портировал его в PDI (у меня больше опыта с R, чем с PDI). – argoneus

+0

Я запустил код 'split(), который вы отправили, и ждал почти час, но он так и не завершился. – argoneus

+0

Пара дополнительных предложений, добавленных вокруг split, которые должны принимать порядка секунды или меньше. Может быть, факторы также заставляют func также замедляться? –

2

Split (х, е) является медленным, если х является фактором и е содержит много различных элементов

Таким образом, этот код, если быстро:

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

Но это очень медленно:

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

И это быстро снова, потому что есть только 25 групп

system.time(split(factor(seq_len(1300000)), sample(25, 1300000, TRUE))) 
Смежные вопросы