Примените функцию rowwise(), используя имена столбцов, чтобы идентифицировать аргументы функции, используя mutate()

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

Вот МВЕ:

# Define simple function
myFunc <- function(a, b, c) a*b^c

# Create tibble of parameters (intentionally out of order)
tbl <- tibble(b = 2:6, a = 1:5, c = -1:3)

# Apply function by listing columns explicitly
tbl |> rowwise() |> mutate(myFunc(a = a, b= b, c=c))

# Fail to apply function...
tbl |> rowwise() |> mutate(myFunc())

# Fail again...
tbl |> rowwise() |> mutate(myFunc(.data))
# Continue ad nauseum...

Готовы ли вы добавить ... к определению функции?

the-mad-statter 01.07.2024 21:00

@the-mad-statter Да!

mikemtnbikes 01.07.2024 21:46
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
77
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

Одним из вариантов было бы использовать семейство функций purrr::pmap, например. используя pmap_dbl, вы можете сделать:

myFunc <- function(a, b, c) a * b^c

library(dplyr, warn.conflicts = FALSE)
library(purrr)

tbl <- tibble(b = 2:6, a = 1:5, c = -1:3)

tbl %>%
  mutate(res = pmap_dbl(., myFunc))
#> # A tibble: 5 × 4
#>       b     a     c    res
#>   <int> <int> <int>  <dbl>
#> 1     2     1    -1    0.5
#> 2     3     2     0    2  
#> 3     4     3     1   12  
#> 4     5     4     2  100  
#> 5     6     5     3 1080

Боже мой, это так просто и элегантно, но я не могу заставить это работать в более сложной ситуации, которую пытаюсь выполнить. В более сложном примере функция имеет аргументы по умолчанию и возвращает тиббл, а не двойное значение. В результате я попробовал синтаксис `pmap(., myMoreComplexFunction), .keep = "none")` и получаю ошибку `! объект '.' не найдено. Есть идеи, почему?

mikemtnbikes 01.07.2024 21:59

Ааа, я понял, почему приведенный выше синтаксис не удался. Я использовал трубку |> в mutate, а не в %>%. Теперь работает!!!

mikemtnbikes 01.07.2024 22:07

Ваши последние два вызова завершаются неудачей, потому что myFunc ожидает три вектора, а не ноль аргументов или один data.frame.

Вы можете изменить его, чтобы последний вызов работал, придав ему аргумент, который получает местоимение данных .data:

myFunc <- function(x) x$a * x$b ^ x$c

tbl |> rowwise() |> mutate(myFunc(.data))

Помните, что .data не является обычным data.frame, поэтому вы не можете использовать x так, как если бы он был.

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

Onyambu 01.07.2024 21:11

@Оньямбу, вообще-то, я этого ожидаю. Но вы всегда можете его завернуть.

Konrad Rudolph 01.07.2024 21:21

Я бы предпочел этого не делать, но из любопытства... как бы вы это обернули?

mikemtnbikes 01.07.2024 21:54

@mikemtnbikes Ну myFuncWrapper = function (x) myFunc(x$a, x$b, x$c).

Konrad Rudolph 01.07.2024 22:10

Вы можете использовать любое из следующих действий и выполнить привязку к данным:

do.call(myFunc, tbl)
[1]    0.5    2.0   12.0  100.0 1080.0

exec(myFunc, !!!tbl)
[1]    0.5    2.0   12.0  100.0 1080.0

NB: Что, если бы в tbl было больше столбцов, некоторые из которых не определены в функции? Затем используйте:

eval(body(myFunc), tbl)
[1]    0.5    2.0   12.0  100.0 1080.0

Обратите внимание, что следующее не удается:

tbl$d <- 10
do.call(myFunc, tbl)
Error in (function (a, b, c)  : 
  unused argument (d = c(10, 10, 10, 10, 10))

tbl %>%
+     mutate(res = pmap_dbl(., myFunc))
Error in `mutate()`:
ℹ In argument: `res = pmap_dbl(., myFunc)`.
Caused by error in `pmap_dbl()`:
ℹ In index: 1.
Caused by error in `.f()`:
! unused argument (d = .l[[4]][[i]])
Run `rlang::last_trace()` to see where the error occurred.

eval(body(myFunc), tbl) # THIS RUNS
[1]    0.5    2.0   12.0  100.0 1080.0

Наконец, самый безопасный способ — изменить формальные параметры функции напрямую с помощью данных. Это делается для того, чтобы гарантировать, что если в функции есть значения по умолчанию, эти значения сохраняются при изменении значений в списке. Обратите внимание, что eval(body(fun), ...) может потерпеть неудачу, если функция имеет значения по умолчанию. Используйте код ниже

tbl$e <- "nothing"
do.call(myFunc, modifyList(a<-formals(myFunc), tbl)[names(a)])
[1]    0.5    2.0   12.0  100.0 1080.0

Примечание:

Если ваша функция не векторизована (что редко случается с большинством функций R), вызовите mapply

do.call(mapply, c(myFunc, modifyList(a<-formals(myFunc), tbl)[names(a)]))
[1]    0.5    2.0   12.0  100.0 1080.0

Ваш ответ игнорирует вызов rowwise(). Для примера функции, предоставленной OP, это не имеет значения, но я предполагаю, что она присутствовала по какой-то причине.

Konrad Rudolph 01.07.2024 21:22

@KonradRudolph по строкам предназначен для векторизации. Это не имеет никакого эффекта, если функция сама векторизована.

Onyambu 01.07.2024 21:24

Да, в том-то и дело: предположительно функция OP не векторизована.

Konrad Rudolph 01.07.2024 21:25

@KonradRudolph Я имел в виду другие мои решения. Я удалил pmap, как только понял, что он был опубликован. Ваш пройдет, поскольку вы изменили функцию. Извините за это.

Onyambu 01.07.2024 21:29

Мы можем использовать !!! как показано:

library(dplyr)
library(rlang)

myFunc <- function(a, b, c) a*b^c
tbl <- tibble(b = 2:6, a = 1:5, c = -1:3)

tbl %>%
  rowwise %>%
  mutate(my = myFunc(!!!syms(set_names(names(.))))) %>%
  ungroup

предоставление

# A tibble: 5 × 4
      b     a     c     my
  <int> <int> <int>  <dbl>
1     2     1    -1    0.5
2     3     2     0    2  
3     4     3     1   12  
4     5     4     2  100  
5     6     5     3 1080  

Хороший пример! Синтаксис более сложен, чем принятый ответ, но помогает мне понять!!! лучше.

mikemtnbikes 01.07.2024 23:03

Да, но принятый ответ не отвечает на заданный вопрос о том, как «Применить функцию rowwise()».

G. Grothendieck 02.07.2024 13:36

Верно, но это довольно тривиальная настройка. Еще добавлю.

mikemtnbikes 03.07.2024 01:01

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