Как использовать пользовательскую функцию в dplyr group_by - PullRequest
1 голос
/ 30 апреля 2019

Я пытаюсь использовать пользовательскую функцию (которая возвращает скаляр) для суммирования или изменения в потоке dplyr, который включает group_by.Функция работает, когда я вызываю ее напрямую, однако всякий раз, когда она следует за group_by, она не работает.

См. Мой код для того, что я пробовал.Мне удалось заставить это работать, но я чувствую, что это своего рода хакерский способ - я хочу понять, почему это не работает, поскольку я ожидал бы это:

Загрузка данных и определение функции коэффициента Джини

## Load required libraries
library(dplyr)
library(tidyr)
library(ROCR)

set.seed(0)
## Generate fake data
df1 <- data.frame(predictions = seq(0,1,.01), date = seq(as.Date("2009-01-01"), by = "month", length.out = 101), labels = sample(c(0,1), replace=TRUE, size=101), grouping = rep('a',101))
df2 <- data.frame(predictions = seq(0,1,.01), date = seq(as.Date("2010-01-01"), by = "month", length.out = 101), labels = sample(c(0,1), replace=TRUE, size=101), grouping = rep('b',101))

df <- rbind(df1,df2)

## Gini coefficient calculation function
dplyr_Gini <- function(df, predictions, labels, label.ordering = NULL,...){
  predictions = enquo(predictions)
  labels = enquo(labels)

  predictions <- df %>% select(!!predictions) %>% .[[1]]
  labels <- df %>% select(!!labels) %>% .[[1]]

  if(length(unique(labels)) != 2){
    return(NA)
  }

  pred <- prediction(predictions, labels, label.ordering)
  auc.perf = performance(pred, measure = "auc")
  gini =  2*auc.perf@y.values[[1]] - 1
  return(gini)
}

## test dplyr_Gini - works as expected
dplyr_Gini(df1,predictions, labels)
> [1] -0.05494505
dplyr_Gini(df2,predictions, labels)
> [1] 0.09456265

Не работает - используйте dplyr_Gini после group_by.

## Wrapper function for using dplyr_Gini in group_by
calc_Gini <- function(df, group, predictions, labels){
  predictions <- enquo(predictions)
  labels = enquo(labels)

  df %>% filter(grouping %in% group) %>%
    group_by(grouping) %>% 
    summarise(min.date = min(date),
              max.date = max(date),
              Gini = dplyr_Gini(.,!!predictions, !!labels)) %>% 
    ungroup()  
}

calc_Gini(df,group = c('a','b'),predictions, labels)
> # Adding missing grouping variables: `grouping`
> # Adding missing grouping variables: `grouping`
> # Error in prediction(predictions, labels, label.ordering) : 
> # Format of predictions is invalid. 

Работайте - используйте dplyr_Gini после group_by, используя do и unnest

## Wrapper function that works for using dplyr_Gini in group_by - but is kind of hacky.
calc_Gini_working <- function(df, group, predictions, labels){
  predictions <- enquo(predictions)
  labels = enquo(labels)

  df %>% filter(grouping %in% group) %>%
    group_by(grouping) %>% 
    mutate(min.date = min(date),
              max.date = max(date)) %>% 
    group_by(grouping, min.date, max.date) %>% 
    do(Gini = dplyr_Gini(.,!!predictions, !!labels)) %>% 
    unnest() %>% 
    ungroup()

}

calc_Gini_working(df,group = c('a','b'),predictions, labels)
>
# A tibble: 2 x 4
  grouping min.date   max.date      Gini
  <fct>    <date>     <date>       <dbl>
1 a        2009-01-01 2017-05-01 -0.0549
2 b        2010-01-01 2018-05-01  0.0946

У меня такое впечатлениечто функция calc_Gini будет работать, поскольку я только что добавил свою пользовательскую функцию (dplyr_Gini) в суммирование, которое следует за group_by.

Как видите, если я оберну dplyr_Gini в do и затем unnest результат работает - но я не уверен почему.

1 Ответ

0 голосов
/ 30 апреля 2019

В зависимости от способа построения dplyr_Gini, один из вариантов - group_split, а затем использовать map

library(tidyverse)
calc_Gini <- function(df, group, predictions, labels){
  predictions <- enquo(predictions)
  labels = enquo(labels)

  df %>% filter(grouping %in% group) %>%
    group_split(grouping, remove = FALSE) %>% 
    map_dfr(., ~               
              tibble(grouping = first(.x$grouping), min.date = min(.x$date), 
                     max.date = max(.x$date), 
                     Gini = dplyr_Gini(.x, !!predictions, !!labels)))

}


calc_Gini(df,group = c('a','b'),predictions, labels)
# A tibble: 2 x 4
#  grouping min.date   max.date      Gini
#  <fct>    <date>     <date>       <dbl>
#1 a        2009-01-01 2017-05-01 -0.0549
#2 b        2010-01-01 2018-05-01  0.0946
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...