Фильтровать данные внутри функции через do.call - PullRequest
0 голосов
/ 26 апреля 2019

Данные:

 data <- structure(list(index = c(1, 2, 3, 4, 5, 6), 
hour = c(13, 13, 13, 1, 1, 1), minutes = c(31, 
     31, 32, 36, 36, 36)), class = "data.frame", row.names = c(1067L, 
    1069L, 1070L, 1072L, 1073L, 1074L))

использование do.call:

func <- function(hourFilt, minutesFilt){
  filt <- data[data$hour == hourFilt & data$minutes == minutesFilt, ]$idx
  sum(filt)
}

do.call(func, list(hourFilt = 1:5, minutesFilt = 31:35))

Мне известно, что означает предупреждение:

Предупреждающие сообщения: 1:В данных $ hour == hourFilt: длинная длина объекта не кратна короткой длине объекта

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

Ожидаемый результат:

mapply(func, hourFilt = 1:5, minutesFilt = 31:35)
1 2 0 0 0 

Однако я бы предпочел использовать do.call(), поскольку он быстрее.

Изменить: Добавление намерения Я хочу отфильтровать набор данных из 25k-200k строк в течение определенного времени.Фильтрация исходного набора данных приведет к трем строкам.И для этого результата я хочу суммировать данную переменную - здесь: индекс.Этот процесс будет повторяться несколько сотен раз.Поэтому я посмотрел в mapply(), do.call().Производительность имеет значение, поэтому я предпочитаю do.call().

1 Ответ

3 голосов
/ 26 апреля 2019

Цель do.call не в том, чтобы запустить функцию несколько раз, как это делает mapply, а в том, чтобы запустить функцию один раз над списком элементов.Это очень удобно при работе с большими списками и при попытке применить одну функцию к всем аргументам списка.Типичным примером будет do.call(cbind,list), если вы хотите создать таблицу, в которой каждый столбец является элементом списка.

Итак, когда вы запускаете do.call(func, list(hourFilt = 1:5, minutesFilt = 31:35)) R работает

func(hourFilt = 1:5, minutesFilt = 31:35)

И, таким образом, вы получаете свои ошибки.Все элементы списка сразу передаются на аргументы вашего func().

Я думаю, что mapply() может быть лучшим решением вашей проблемы.Если вас беспокоит производительность, вы можете попробовать mcmapply() из пакета parallel, который может распараллелить вычисления (не в Windows).

corenum <- parallel::detectCores()-1
parallel::mcmapply(func,hourFilt=1:5,minutesFilt=31:35,mc.cores=corenum)

Или, если вы работаете в Windows, чем большегромоздкие parSapply() могут работать для вас:

corenum <- parallel::detectCores()-1
cl<-parallel::makeCluster(corenum)

#export the objects so that the parallel sockets can use them
parallel::clusterExport(cl,c("func","hourFilt","minutesFilt","data"))

result<-parallel::parSapply(cl,1:length(hourFilt),function(i){
  func(hourFilt[i],minutesFilt[i])
})

PS: С вашим набором данных ожидаемый результат должен быть 0 0 0 0 0

...