R использует только 13% моего процессора

Система:

ОС - Windows 7

Оперативная память — 8 ГБ

Процессор - Intel i7

Версия R — Всегда обновляйте ее

Проблема:

R использует только 13% (т.е. 1 из 8 ядер) моего процессора Intel i7. Я хочу задействовать несколько ядер для более быстрого выполнения моего кода. Но, к сожалению, не в состоянии.

Попытки:

Начал использовать пакеты Parallel, Snow, Snowfall, даже настроил их на использование 8 ядер, но, к сожалению, я не использую ни одну из функций применения, чтобы использовать предоставляемые ими пользовательские функции (например, mcapply, sflapply).

for (i in 1:number.of.accounts){
  if (is.na(s$rev2012[i]) == "FALSE" && is.na(s$rev2013[i]) == "TRUE"){
    loss = rbind(loss, s[i,])
  }
  x = x + 1
}

Фрейм данных «s» в приведенном выше коде содержит около 56 000 строк с 14 столбцами. «rev» означает доход. Что я пытаюсь сделать, так это то, что если в 2012 году будет выручка, а в 2013 году нет, то мы «потеряли» этого клиента. Я использую «x», чтобы вести подсчет скорости.

Этот фрагмент кода требует много времени для запуска, и я еще не дал ему закончить. Когда я прерываю, я вижу, что не так уж много продвинулось.

Любая помощь в разблокировке всех ядер для запуска этого фрагмента кода была бы действительно здоровой.

Спасибо!


person Pragith    schedule 13.03.2014    source источник
comment
Мне проще всего использовать foreach для параллельных вычислений в Windows. Однако ускорение, которого можно достичь за счет распараллеливания, крайне ограничено (количеством процессоров). Если вы перепишете свой код с векторизованным подходом вместо цикла for, вы можете ожидать ускорения на порядки.   -  person Roland    schedule 13.03.2014
comment
Попробуйте loss <- s[!is.na(s$rev2012) & is.na(s$rev2013),]. Это не распараллеливает его, а вместо этого использует векторизованную форму, для которой оптимизирован R.   -  person shadow    schedule 13.03.2014
comment
пожалуйста, проверьте stackoverflow.com/questions /1395309/   -  person Nachiket Kate    schedule 13.03.2014
comment
Спасибо за ваши ответы. Роланд, не могли бы вы помочь мне с псевдокодом для foreach? Невозможно найти помощь для него. тень, спасибо за ваш код. Я пробую это сейчас. Обновлю, если увижу улучшения. Я все еще ищу разблокировку своих ядер конкретно.   -  person Pragith    schedule 13.03.2014
comment
joyofdata.de/blog/   -  person Raffael    schedule 13.03.2014
comment
Спасибо большое Рафаэль. Я постараюсь обновить здесь.   -  person Pragith    schedule 13.03.2014


Ответы (2)


Поскольку R изначально не поддерживает параллельную обработку, вы должны добавить в свой скрипт некоторый шаблон, чтобы он использовал все 8 ядер.

Ознакомьтесь с пакетом doParallel. Вот виньетка, показывающая, как использовать < пакет strong>doParallel. Также см. этот вопрос о как использовать фрагментацию для повышения производительности.

Это потребует от вас использования цикла foreach, который можно распараллелить с %dopar%, вместо цикла for.

person Christopher Louden    schedule 13.03.2014
comment
doParallel творит чудеса, но использует более 6 ГБ моей оперативной памяти (из 8 ГБ), а загрузка процессора составляет менее 3% (даже не 13%, как раньше). В целом код работает еще долго (>10 минут) foreach (i = 1:number.of.accounts) %dopar% if (is.na(s$rev2012[i]) == "FALSE" && is.na(s$rev2013[i]) == "TRUE"){ loss = rbind(loss, s[i,]) } - person Pragith; 14.03.2014

На самом деле есть две проблемы с вашим кодом. Во-первых, вы оцениваете построчно, используя цикл for. Практически нет обстоятельств, при которых это является хорошей практикой в ​​R. Во-вторых, вы добавляете одну строку за раз к loss. Это также очень медленно.

Использование параллельной обработки обеспечит максимум 8-кратное улучшение. Векторизация обеспечит более чем 50-кратное улучшение, а использование data.tables улучшит его еще больше.

df <- data.frame(rev2012=sample(c(NA,1:99),56000,replace=T),
                 rev2013=sample(c(NA,1:99),56000,replace=T))
df   <- cbind(df,matrix(rnorm(56000*12),ncol=12))

for.loop <- function(){
  loss <- c()
  for (i in 1:nrow(df))
    if (is.na(df$rev2012[i]) == "FALSE" && is.na(df$rev2013[i]) == "TRUE") loss = rbind(loss, df[i,])
}

df.vectorized <- function(){
  loss <- with(df,df[!is.na(rev2012) & is.na(rev2013),])
}

library(data.table)
dt <- function(){
  dt <- data.table(df)
  setkey(dt,rev2012,rev2013)
  loss <- dt[!is.na(rev2012)&is.na(rev2013)]
}

library(microbenchmark)
microbenchmark(for.loop(),df.vectorized(),dt(),times=10)
# Unit: milliseconds
#             expr        min         lq     median         uq        max neval
#       for.loop() 3141.53686 3431.99529 3620.90536 3845.81394 3875.92435    10
#  df.vectorized()   38.76076   55.01082   58.97976   64.19538   67.33192    10
#             dt()   28.20870   31.10005   40.54224  165.20777  184.48776    10

Причина, по которой таблицы данных улучшаются только примерно на 33% по сравнению с подходом векторизованного фрейма данных, заключается в том, что 56 000 строк — это не так уж и много. Если бы в df было >1e6 строк, использование data.table определенно было бы лучшим вариантом.

person jlhoward    schedule 13.03.2014
comment
Добавление s в data.table меня беспокоит :( - person Dason; 13.03.2014
comment
В конце у вас есть data.tables вместо data.table несколько раз. - person Dason; 13.03.2014
comment
Эй, спасибо за ваш код и ваше объяснение. Однако мне пришлось убить процесс, потому что это тоже занимало много времени (> 10 минут) для выполнения. - person Pragith; 14.03.2014
comment
@Pragith, я полагаю, ты что-то неправильно понял. Решение data.table должно быть очень быстрым. - person Roland; 14.03.2014