Как передать имена динамических столбцов в dplyr в пользовательскую функцию?

У меня есть набор данных со следующей структурой:

Classes ‘tbl_df’ and 'data.frame':  10 obs. of  7 variables:
 $ GdeName  : chr  "Aeugst am Albis" "Aeugst am Albis" "Aeugst am Albis" "Aeugst am Albis" ...
 $ Partei   : chr  "BDP" "CSP" "CVP" "EDU" ...
 $ Stand1971: num  NA NA 4.91 NA 3.21 ...
 $ Stand1975: num  NA NA 5.389 0.438 4.536 ...
 $ Stand1979: num  NA NA 6.2774 0.0195 3.4355 ...
 $ Stand1983: num  NA NA 4.66 1.41 3.76 ...
 $ Stand1987: num  NA NA 3.48 1.65 5.75 ...

Я хочу предоставить функцию, которая позволяет вычислить разницу между любым значением, и я хотел бы сделать это с помощью функции dplyrs mutate следующим образом: (предположим, что параметры from и to передаются как аргументы)

from <- "Stand1971"
to <- "Stand1987"

data %>%
  mutate(diff = from - to)

Конечно, это не работает, поскольку dplyr использует нестандартную оценку. И я знаю, что теперь есть элегантное решение проблемы с использованием mutate_, и я прочитал это виньетка, но я все еще не могу понять ее.

Что делать?

Вот несколько первых строк набора данных для воспроизводимого примера.

structure(list(GdeName = c("Aeugst am Albis", "Aeugst am Albis", 
"Aeugst am Albis", "Aeugst am Albis", "Aeugst am Albis", "Aeugst am Albis", 
"Aeugst am Albis", "Aeugst am Albis", "Aeugst am Albis", "Aeugst am Albis"
), Partei = c("BDP", "CSP", "CVP", "EDU", "EVP", "FDP", "FGA", 
"FPS", "GLP", "GPS"), Stand1971 = c(NA, NA, 4.907306434, NA, 
3.2109535926, 18.272143463, NA, NA, NA, NA), Stand1975 = c(NA, 
NA, 5.389079711, 0.4382328556, 4.5363022622, 18.749259742, NA, 
NA, NA, NA), Stand1979 = c(NA, NA, 6.2773722628, 0.0194647202, 
3.4355231144, 25.294403893, NA, NA, NA, 2.7055961071), Stand1983 = c(NA, 
NA, 4.6609804428, 1.412940467, 3.7563539244, 26.277246489, 0.8529335746, 
NA, NA, 2.601878177), Stand1987 = c(NA, NA, 3.4767860929, 1.6535933856, 
5.7451770193, 22.146844746, NA, 3.7453183521, NA, 13.702211858
)), .Names = c("GdeName", "Partei", "Stand1971", "Stand1975", 
"Stand1979", "Stand1983", "Stand1987"), class = c("tbl_df", "data.frame"
), row.names = c(NA, -10L))

person grssnbchr    schedule 16.04.2015    source источник
comment
Он не отвечает на ваш вопрос, но, судя по контексту, вам может быть лучше с аккуратным набором данных, который вы могли бы просто использовать lead(x) - x для вычисления разницы между последующими значениями за все годы сразу.   -  person hadley    schedule 16.04.2015


Ответы (2)


Используя последнюю версию dplyr (> = 0.7), вы можете использовать оператор rlang !! (bang-bang).

library(tidyverse)
from <- "Stand1971"
to <- "Stand1987"

data %>%
  mutate(diff=(!!as.name(from))-(!!as.name(to)))

Вам просто нужно преобразовать строки в имена с as.name, а затем вставить их в выражение. К сожалению, мне, кажется, пришлось использовать несколько скобок больше, чем хотелось бы, но оператор !!, похоже, попадает в странный порядок операций.

Исходный ответ, dplyr (0,3- ‹0,7):

Из этой виньетки (vignette("nse","dplyr")) используйте функцию lazyeval interp()

library(lazyeval)

from <- "Stand1971"
to <- "Stand1987"

data %>%
  mutate_(diff=interp(~from - to, from=as.name(from), to=as.name(to)))
person MrFlick    schedule 16.04.2015
comment
Почему этот подход более привлекателен (или предпочтительнее), чем использование paste? - person grssnbchr; 16.04.2015
comment
interp () также помогает захватывать соответствующие среды, что более важно, когда у вас более сложные области видимости или не базовые функции - person MrFlick; 16.04.2015
comment
@wnstnsmth, так же как и среды захвата, интерполяция всегда будет работать независимо от имени переменных. Использование пасты - это просто добавление в ваш код бомбы с часовым механизмом. - person hadley; 16.04.2015
comment
Что, если я хочу, чтобы имя моего нового столбца (в данном примере diff) было динамическим? Та же самая конструкция, похоже, не работает с LHS назначения mutate. - person DanTan; 06.02.2019
comment
@DanTan Используйте mutate(!!diff :=(!!as.name(from))-(!!as.name(to))). := позволяет вам изменить имя нового столбца слева от равных. См. stackoverflow.com/q/26003574/2372064 - person MrFlick; 06.02.2019

Теперь вы можете использовать .data внутри dplyr цепочки.

library(dplyr)
from <- "Stand1971"
to <- "Stand1987"

data %>% mutate(diff = .data[[from]] - .data[[to]])

Другой вариант - использовать sym с bang-bang (!!)

data %>% mutate(diff = !!sym(from) - !!sym(to))

В базе R мы можем использовать:

data$diff <- data[[from]] - data[[to]]
person Ronak Shah    schedule 02.04.2021