Почему я получил разные результаты с помощью функций dplyr SE или NSE

Привет я получил отличные результаты от функции dplyr, когда я использую стандартную оценку через пакет lazyeval.

Вот как воспроизвести что-то похожее на мои настоящие данные с 250-тысячными строками и около 230-тысячными группами. Я хотел бы сгруппировать по id1, id2 и подмножество строк с максимальным (datetime) для каждой группы.

library(dplyr)
# random datetime generation function by Dirk Eddelbuettel
# http://stackru.com/questions/14720983/efficiently-generate-a-random-sample-of-times-and-dates-between-two-dates
rand.datetime <- function(N, st = "2012/01/01", et = "2015/08/13") {
  st <- as.POSIXct(as.Date(st))
  et <- as.POSIXct(as.Date(et))
  dt <- as.numeric(difftime(et,st,unit="sec"))
  ev <- sort(runif(N, 0, dt))
  rt <- st + ev
}

set.seed(42)
# Creating 230000 ids couples
ids <- data_frame(id1 = stringi::stri_rand_strings(23e4, 9, pattern = "[0-9]"), 
                  id2 = stringi::stri_rand_strings(23e4, 9, pattern = "[0-9]"))
# Repeating randomly the ids[1:2000, ] to create groups    
ids <- rbind(ids, ids[sample(1:2000, 20000, replace = TRUE), ])
datas <- mutate(ids, datetime = rand.datetime(25e4))

Когда я использую NSE, я получил 230000 строк

df1 <- 
  datas %>% 
  group_by(id1, id2) %>% 
  filter(datetime == max(datetime))
nrow(df1) #230000

Но когда я использую SE, я получил только 229977 строк

ids <- c("id1", "id2")
filterVar <- "datetime"
filterFun <- "max"
df2 <- 
  datas %>% 
  group_by_(ids) %>% 
  filter_(.dots = lazyeval::interp(~var == fun(var), 
                                   var = as.name(filterVar), 
                                   fun = as.name(filterFun)))
nrow(df2) #229977

Мои две части кода эквивалентны верно? Почему у меня разные результаты? Благодарю.

1 ответ

Решение

Вам нужно будет указать .dots аргумент в group_by_ при указании вектора имен столбцов.

df2 <- datas %>% 
    group_by_(.dots = ids) %>% 
    filter_(.dots = lazyeval::interp(~var == fun(var), 
                               var = as.name(filterVar), 
                               fun = as.name(filterFun)))
nrow(df2)
[1] 230000

Это выглядит как group_by_ может взять имя первого столбца из вектора в качестве единственной переменной группировки, если вы не укажете .dots аргумент. Вы можете проверить это, группируя по id1 только.

df1 <- datas %>% 
    group_by(id1) %>% 
    filter(datetime == max(datetime))
 nrow(df1)
[1] 229977

(Если вы группируете только на id2 количество рядов составляет 229976).

Другие вопросы по тегам