Я собирался задать очень похожий вопрос к этому.По сути, спрашивая, как использовать pmap
в mutate
, не используя имена переменных более одного раза.Вместо этого я опубликую его как «ответ» здесь, поскольку он включает в себя предисловие и ряд опций, которые я нашел, ни один из которых не является полностью удовлетворительным для меня.Надеюсь, кто-то еще сможет ответить, как это сделать.
Я часто хочу использовать purrr::pmap
внутри dplyr::mutate
при работе с data.frame со списком-столбцами.Иногда это включает многократное повторение имен переменных.Я хотел бы иметь возможность сделать это более кратко, используя анонимную функцию, чтобы переменные использовались только один раз, когда передаются в pmap
'.f
аргумент.
Примите этот небольшой набор данных какпример:
library('dplyr')
library('purrr')
df <- tribble(
~x, ~y, ~z,
c(1), c(1,10), c(1, 10, 100),
c(2), c(2,20), c(2, 20, 200),
)
Скажем, функция, которую я хочу применить к каждой строке:
func <- function(x, y, z){c(sum(x), sum(y), sum(z))}
На практике функция будет более сложной, с большим количеством переменных.Функция нужна только один раз, поэтому я бы предпочел не называть ее явно и не засорить мой сценарий и мою рабочую среду.
Вот варианты.Каждый создает точно такой же data.frame, но по-своему.Причина включения avg`` will be come clear.
Note I'm not considering position matching using
.. 1 ,
.. 2` и т. Д., Поскольку это легко испортить.
# Explicitly create a function for `.f`.
# This requires using the variable names (x, y, z) three times.
# It's completely clear what it's doing, but needs a lot of typing.
# It might sometimes fail - see https://github.com/tidyverse/purrr/issues/280
df_explicit <- df %>%
mutate(
avg = x - mean(x),
a = pmap(.l = list(x, y, z), .f = function(x, y, z){ c(sum(x), sum(y), sum(z)) })
)
# Pass the whole of `df` to `.l` and add `...` in an explicit function to deal with any unused columns.
# variable names are used twice.
# `df` will have to be passes explicitly if not using pipes (eg, `mutate(.data = df, a = pmap(.l = df, ...`).
# This is probably inefficient for large datasets.
df_dots <- df %>%
mutate(
avg = x - mean(x),
a = pmap(.l = ., .f = function(x, y, z, ...){ c(sum(x), sum(y), sum(z)) })
)
# Use `pryr::f` (as discussed in https://stackoverflow.com/a/51123520/4269699).
# Variable names are used twice.
# Potentially unexpected behaviour.
# Not obvious to the casual reader why the extra `pryr::f` is needed and what it's doing
df_pryrf <- df %>%
mutate(
avg = x - mean(x),
a = pmap(.l = list(x,y,z), .f = pryr::f({c(sum(x), sum(y), sum(z))} ))
)
# Use `rowwise()` similar to this: https://stackoverflow.com/a/47734073/4269699
# Variable names are used once.
# It will mess up any vectorised functions used elsewhere in mutate, hence the two `mutate()`s
df_rowwise <- df %>%
mutate( avg = x - mean(x) ) %>%
rowwise() %>%
mutate( a = list( {c(sum(x), sum(y), sum(z))} ) ) %>%
ungroup()
# Use Romain Francois' neat {rap} package.
# Variable names used once.
# Like `rowwise()` it will mess up any vectorised functions so it needs two `mutate()`s for this particular problem
#
library('rap') #devtools::install_github("romainfrancois/rap")
df_rap <- df %>%
mutate( avg = x - mean(x) ) %>%
rap( a = ~ c(sum(x), sum(y), sum(z)) )
# Another solution discussed here https://stackoverflow.com/a/51123520/4269699 doesn't seem to work inside `mutate()`, but maybe could be tweaked?
# Like the `pryr::f` solution, it's not immediately obvious what the purpose of the `with(list(...` bit is.
df_with <- df %>%
mutate(
avg = x-mean(x),
a = pmap(.l = list(x,y,z), .f = ~with(list(...), { c(sum(x), sum(y), sum(z))} ))
)
Насколько я знаю, это варианты, исключая сопоставление позиций,
В идеале было бы возможно что-то подобное следующему, где функция qmap
знает, как найти (в ряд) переменные x
, y
и z
из объекта, переданного в mutate
s.data
аргумент.
df_new <- df %>%
mutate(
avg = x-mean(x),
a = qmap( ~c(sum(x), sum(y), sum(z)) )
)
Но я не знаю, как это сделать, поэтому рассмотрим это только частичный ответ.
Вопросы, связанные с данной: