Как определить, сгруппирован ли data.frame по dplyr из подфункции?

У меня есть пакет R, в котором некоторые функции предназначены для обычного вызова внутри функций dplyr, изменяющих или суммирующих.

newdata <- dplyr::mutate(group_by(olddata, col1), newcol = myfunc(col1))

Однако иногда пользователи могут забыть сгруппировать свои данные, прежде чем помещать их в вызов mutate или summate.

newdata <- dplyr::mutate(olddata, newcol = myfunc(col1))

Когда фрейм данных не сгруппирован первым, функции пакета будут давать бессмысленные результаты. Однако ошибок или предупреждений как таковых не будет, из-за чего пользователи могут не знать причину проблемы.

Я хотел бы добавить Warning() в код myfunc, когда myfunc обнаруживает, что входные данные не поступают из сгруппированного data.frame. Однако я не могу понять, как myfunc может определить, поступают ли данные из сгруппированного data.frame. Похоже, что mutate передает вектор только myfunc, поэтому и dplyr::is.grouped_df, и inherits(x, "grouped_df") возвращают false.

Что я хотел бы:

myfunc <- function(x) {if (comes.from.grouped.df) {print("grouped")} else {print("ungrouped")}}

mutate(olddata, newcol = myfunc(col1))
'ungrouped'

mutate(group_by(olddata, col1), newcol = myfunc(col1))
'grouped'
'grouped'
'grouped'

Вы можете использовать cur_data_all(), а затем проверить is.grouped_df

akrun 15.02.2023 21:12

см. ?group_data, от dplyr

Ric Villalba 15.02.2023 21:13
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Если вы хотите, чтобы ваша функция использовалась в определенном контексте и выдавала предупреждение, если фрейм данных не сгруппирован, вы можете сделать:

library(tidyverse)

myfunc <- function(x) {
  if (all(ls(envir = parent.frame()) == "~")) {
    ss <- sys.status()
    funcs <- sapply(ss$sys.calls, function(x) deparse(as.list(x)[[1]]))
    wf <- which(funcs == "mutate")
    if (length(wf) == 0) stop("`myfunc` must be called from inside `mutate`")
    wf <- max(wf)
    data <- eval(substitute(.data), ss$sys.frames[[wf]])
    if (!inherits(data, "grouped_df")) {
      warning("`myfunc` called on an ungrouped data frame / tibble.")
    }
    return(x^2)
  }
  stop("`myfunc` must be called from inside `mutate`")
}

При использовании вне mutate получаем ошибку:

myfunc(1:10)
#> Error in myfunc(1:10): `myfunc` must be called from inside `mutate`

С несгруппированным фреймом данных или табличкой мы получаем предупреждение:

tibble(iris) %>% 
  mutate(x = myfunc(Sepal.Length))
#> Warning in myfunc(Sepal.Length): `myfunc` called on an ungrouped data frame /
#> tibble.
#> # A tibble: 150 x 6
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species     x
#>           <dbl>       <dbl>        <dbl>       <dbl> <fct>   <dbl>
#>  1          5.1         3.5          1.4         0.2 setosa   26.0
#>  2          4.9         3            1.4         0.2 setosa   24.0
#>  3          4.7         3.2          1.3         0.2 setosa   22.1
#>  4          4.6         3.1          1.5         0.2 setosa   21.2
#>  5          5           3.6          1.4         0.2 setosa   25  
#>  6          5.4         3.9          1.7         0.4 setosa   29.2
#>  7          4.6         3.4          1.4         0.3 setosa   21.2
#>  8          5           3.4          1.5         0.2 setosa   25  
#>  9          4.4         2.9          1.4         0.2 setosa   19.4
#> 10          4.9         3.1          1.5         0.1 setosa   24.0
#> # ... with 140 more rows

И он работает без нареканий, если табличка сгруппирована:

tibble(iris) %>% 
  group_by(Species) %>%
  mutate(x = myfunc(Sepal.Length))
#> # A tibble: 150 x 6
#> # Groups:   Species [3]
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width Species     x
#>           <dbl>       <dbl>        <dbl>       <dbl> <fct>   <dbl>
#>  1          5.1         3.5          1.4         0.2 setosa   26.0
#>  2          4.9         3            1.4         0.2 setosa   24.0
#>  3          4.7         3.2          1.3         0.2 setosa   22.1
#>  4          4.6         3.1          1.5         0.2 setosa   21.2
#>  5          5           3.6          1.4         0.2 setosa   25  
#>  6          5.4         3.9          1.7         0.4 setosa   29.2
#>  7          4.6         3.4          1.4         0.3 setosa   21.2
#>  8          5           3.4          1.5         0.2 setosa   25  
#>  9          4.4         2.9          1.4         0.2 setosa   19.4
#> 10          4.9         3.1          1.5         0.1 setosa   24.0
#> # ... with 140 more rows

Created on 2023-02-15 with reprex v2.0.2

Привет, это действительно здорово, спасибо! У меня есть одно продолжение: как это можно изменить, чтобы оно работало, когда вход представляет собой data.frame, а не табличку? Как сейчас написано, запуск: mutate(iris, x = myfunc(Sepal.Length)) выдает ошибку object '.' not found. Копаясь в этом, eval(quote(.), parent.frame()) терпит неудачу, когда вход представляет собой data.frame, а не tibble, но all(ls(envir = parent.frame()) == "~") возвращает TRUE для ввода data.frame. Как я могу изменить это для поддержки необработанных входных данных data.frame? Извините, я не понимаю этого достаточно хорошо, чтобы понять, как это сделать.

mikeblazanin 16.02.2023 23:29

@mikeblazanin это не имеет ничего общего с табличкой и фреймом данных. quote(.) работает только в том случае, если вы передадите фрейм данных / табличку. Я изменил его, чтобы он работал в любом случае, используя quote(.data)

Allan Cameron 16.02.2023 23:53

Ааааа, отлично! Хотя теперь, когда я запускаю вашу отредактированную функцию, которая использует quote(.data) с третьим блоком кода: tibble(iris) %>% group_by(Species) %>% mutate(x = myfunc(Sepal.Length)) выводит первую ошибку: myfunc called on an ungrouped data frame / tibble. Знаете, почему это может быть так?

mikeblazanin 17.02.2023 22:59

@mikeblazanin мой плохой. Кажется, что .data должен оцениваться в том же системном фрейме, где был вызван mutate, иначе он будет интерпретировать .data как местоимение .data tidyverse (которое может быть отдельной группой в сгруппированном наборе). Я изменил функцию, чтобы найти правильный кадр оценки.

Allan Cameron 17.02.2023 23:28

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