Я пытаюсь понять, как писать функции суммирования Rcpp, которые будут быстрыми с dplyr. Мотивация для этого - функция, для которой dplyr, похоже, не имеет эквивалента, однако для простоты я собираюсь использовать пример простого взятия последнего элемента вектора.
В приведенном ниже коде я рассматриваю три разные функции, чтобы получить последний элемент вектора и применить их, используя как tapply, так и dplyr group_by / summarize.
library(dplyr)
library(microbenchmark)
library(Rcpp)
n <- 5000
df <- data.frame(grp = factor(rep(1:n, 2)), valn = rnorm(2L*n), stringsAsFactors = F)
dplyr_num_last_element <- function() df %>% group_by(grp) %>% summarise(valn = last(valn))
dplyr_num_last_element_r <- function() df %>% group_by(grp) %>% summarise(valn = last_r(valn))
dplyr_num_last_element_rcpp <- function() df %>% group_by(grp) %>% summarise(val = last_rcpp(valn))
tapply_num_last_element <- function() tapply(df$valn, df$grp, FUN = last)
tapply_num_last_element_r <- function() tapply(df$valn, df$grp, FUN = last_r)
tapply_num_last_element_rcpp <- function() tapply(df$valn, df$grp, FUN = last_rcpp)
last_r <- function(x) {
x[1]
}
cppFunction('double last_rcpp(NumericVector x) {
int n = x.size();
return x[n-1];
}')
microbenchmark(dplyr_num_last_element(), dplyr_num_last_element_r(), dplyr_num_last_element_rcpp(), tapply_num_last_element(), tapply_num_last_element_r(), tapply_num_last_element_rcpp(), times = 10)
Unit: milliseconds
expr min lq mean median uq max neval
dplyr_num_last_element() 6.895850 7.088472 8.264270 7.766421 9.089424 11.00775 10
dplyr_num_last_element_r() 205.375404 214.481520 220.995218 220.107130 225.971179 238.62544 10
dplyr_num_last_element_rcpp() 211.593443 216.000009 222.247786 221.984289 228.801007 230.50220 10
tapply_num_last_element() 97.082102 99.528712 101.955668 101.717887 104.370319 109.26982 10
tapply_num_last_element_r() 6.101055 6.550065 7.386442 7.069754 7.589164 9.98025 10
tapply_num_last_element_rcpp() 14.173171 15.145711 16.102816 15.400562 16.053229 22.00147 10
Мои общие вопросы:
1) Почему dplyr_num_last_element_r занимает в среднем 220 мс, а tapply_num_last_element_r занимает 7 мс.
2) Есть ли способ написать мою собственную последнюю функцию для использования с dplyr, но потребуется ли ей больше порядка 7 мс?
Спасибо!
data.table
:library(data.table); dt <- data.table(df); setkey(dt, grp); DT_num_last_element_r <- function() dt[, last_r(valn), grp]
- person pogibas   schedule 06.09.2017