如何将 dplyr 中的动态列名传递给自定义函数?

Posted

技术标签:

【中文标题】如何将 dplyr 中的动态列名传递给自定义函数?【英文标题】:How to pass dynamic column names in dplyr into custom function? 【发布时间】:2015-06-23 01:53:46 【问题描述】:

我有一个具有以下结构的数据集:

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 函数来做到这一点:(假设参数fromto 是作为参数传递)

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

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

当然,这不起作用,因为dplyr 使用非标准评估。而且我知道现在有一个使用mutate_ 的优雅解决方案,并且我已经阅读了this vignette,但我仍然无法理解它。

怎么办?

这是一个可重现示例的数据集的前几行

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))

【问题讨论】:

它没有回答你的问题,但从上下文猜测,你可能会更好地使用一个整洁的数据集,你可以使用 lead(x) - x 来计算所有年份的后续值之间的差异一次。 【参考方案1】:

使用最新版本的 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-

从该小插曲 (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)))

【讨论】:

为什么这种方法比使用paste 更“性感”(或首选)? interp() 也有助于捕获适当的环境,这在您有更复杂的作用域或非基本函数时更为重要 @wnstnsmth 以及捕获环境,interp appraoch 将始终工作,无论变量的名称如何。使用 paste 只是在你的代码中放了一个定时错误炸弹。 如果我希望我的新列名(在本例中为差异)也是动态的怎么办?相同的构造似乎不适用于 mutate assignment 的 LHS。 @DanTan 使用mutate(!!diff :=(!!as.name(from))-(!!as.name(to))):= 允许您更改等号左侧的新列的名称。见***.com/q/26003574/2372064【参考方案2】:

您现在可以在dplyr 链中使用.data

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

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

另一种选择是将sym 与bang-bang (!!) 一起使用

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

在base R中,我们可以使用:

data$diff <- data[[from]] - data[[to]]

【讨论】:

这个答案是完美的,但是在代码的其他部分我使用胶水语法var 来做到这一点。但是,它在这种情况下不起作用。 dplyr 现在可以使用的胶水语法中是否有 .data 等效项? 你试过.data[var] 吗?您也许可以就您的具体情况提出一个新问题。

以上是关于如何将 dplyr 中的动态列名传递给自定义函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何将列名作为参数传递给 dplyr 中的函数?

在 R 中:将列名作为参数传递,并在 dplyr::mutate() 和 lazyeval::interp() 的函数中使用它

如何将变量传递给自定义 Django 模板加载器?

如何将 crud 表中的行值传递给自定义提交按钮

在Delphi中如何使用SQL自定义函数,参数怎样传递给自定义函数?

XSLT:如何将节点值传递给自定义 xsl:function ?