我想创建一个函数,它接受一个数据帧和一个包含列名的字符向量作为输入,并以一种安全的方式在其中使用整齐的引用函数。
我相信我有一个我想做的工作的例子。我想知道是否有更优雅的解决方案,或者我对这个问题的想法不正确(也许我不想这么做?)。据我所知,为了避免变量作用域问题,我需要将列名包装在.data[[]中,并在取消引用之前将其作为表达式。
关于之前的问题,这个答案是正确的,但我想将代码抽象为一个函数。github问题询问了这个问题,但使用rlang::syms在我看来是行不通的,因为列标签与. data的组合使其成为表达式而不是符号。这里和这里解决了问题,但据我所知,没有考虑到一个微妙的错误,即如果变量在数据框中不作为列标签存在,或者解决方案不适用于输入是标签向量的情况,它们可能会从环境中泄漏。
# Setup
suppressWarnings(suppressMessages(library("dplyr")))
suppressWarnings(suppressMessages(library("rlang")))
# define iris with and without Sepal.Width column
iris <- tibble::as_tibble(iris)
df_with_missing <- iris %>% select(-Sepal.Width)
# This should not be findable by my function
Sepal.Width <- iris$Sepal.Width * -1
################
# Now lets try a function for which we programmatically define the column labels
programmatic_mutate_y <- function(df, col_names, safe = FALSE) {
# Add .data[[]] to the col_names to make evalutation safer
col_exprs <- rlang::parse_exprs(
purrr::map_chr(
col_names,
~ glue::glue(stringr::str_c('.data[["{.x}"]]'))
)
)
output <- dplyr::mutate(df, product = purrr::pmap_dbl(list(!!!col_exprs), ~ prod(...)))
output
}
################
# The desired output
testthat::expect_error(programmatic_mutate_y(df_with_missing, c("Sepal.Width", "Sepal.Length")))
programmatic_mutate_y(iris, c("Sepal.Width", "Sepal.Length"))
#> # A tibble: 150 x 6
#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species product
#> <dbl> <dbl> <dbl> <dbl> <fct> <dbl>
#> 1 5.1 3.5 1.4 0.2 setosa 17.8
#> 2 4.9 3 1.4 0.2 setosa 14.7
#> 3 4.7 3.2 1.3 0.2 setosa 15.0
#> 4 4.6 3.1 1.5 0.2 setosa 14.3
#> 5 5 3.6 1.4 0.2 setosa 18
#> 6 5.4 3.9 1.7 0.4 setosa 21.1
#> 7 4.6 3.4 1.4 0.3 setosa 15.6
#> 8 5 3.4 1.5 0.2 setosa 17
#> 9 4.4 2.9 1.4 0.2 setosa 12.8
#> 10 4.9 3.1 1.5 0.1 setosa 15.2
#> # … with 140 more rows
由reprex包(v0.3.0)在2019-08-09创建
我们可以将col_names
转换为具有parse_expr
和粘贴
的单个表达式,然后在以mutate
进行评估时取消引用:
library(dplyr)
library(rlang)
programmatic_mutate_y <- function(df, col_names){
mutate(df, product = !!parse_expr(paste(col_names, collapse = "*")))
}
输出:
> parse_expr(paste(c("Sepal.Width", "Sepal.Length"), collapse = "*"))
Sepal.Width * Sepal.Length
> programmatic_mutate_y(df_with_missing, c("Sepal.Width", "Sepal.Length"))
> Error: object 'Sepal.Width' not found
> programmatic_mutate_y(iris, c("Sepal.Width", "Sepal.Length"))
# A tibble: 150 x 6
Sepal.Length Sepal.Width Petal.Length Petal.Width Species product
<dbl> <dbl> <dbl> <dbl> <fct> <dbl>
1 5.1 3.5 1.4 0.2 setosa 17.8
2 4.9 3 1.4 0.2 setosa 14.7
3 4.7 3.2 1.3 0.2 setosa 15.0
4 4.6 3.1 1.5 0.2 setosa 14.3
5 5 3.6 1.4 0.2 setosa 18
6 5.4 3.9 1.7 0.4 setosa 21.1
7 4.6 3.4 1.4 0.3 setosa 15.6
8 5 3.4 1.5 0.2 setosa 17
9 4.4 2.9 1.4 0.2 setosa 12.8
10 4.9 3.1 1.5 0.1 setosa 15.2
# ... with 140 more rows
我认为你把事情搞复杂了。使用< code>_at变量,您几乎可以在每个< code>dplyr函数中使用字符串作为参数。< code>purrr::pmap_dbl()用于按行映射计算。
programmatic_mutate_y_v1 <- function(df, col_names, safe = FALSE) {
df["product"] <- purrr::pmap_dbl(dplyr::select_at(df,col_names),prod)
return(df)
}
programmatic_mutate_y_v1(iris, c("Sepal.Width", "Sepal.Length"))
# A tibble: 150 x 6
Sepal.Length Sepal.Width Petal.Length Petal.Width Species product
<dbl> <dbl> <dbl> <dbl> <fct> <dbl>
1 5.1 3.5 1.4 0.2 setosa 17.8
2 4.9 3 1.4 0.2 setosa 14.7
3 4.7 3.2 1.3 0.2 setosa 15.0
4 4.6 3.1 1.5 0.2 setosa 14.3
5 5 3.6 1.4 0.2 setosa 18
6 5.4 3.9 1.7 0.4 setosa 21.1
7 4.6 3.4 1.4 0.3 setosa 15.6
8 5 3.4 1.5 0.2 setosa 17
9 4.4 2.9 1.4 0.2 setosa 12.8
10 4.9 3.1 1.5 0.1 setosa 15.2
# ... with 140 more rows
有没有一种更简洁的方法从带有数据库后端的tbl中获得dplyr tbl的一列作为向量(即数据帧/表不能直接子集)? 那太容易了,所以 但似乎有点笨拙。
我试图把我对plyr的理解转移到dplyr中,但是我不知道如何按多个列分组。 在将plyr示例翻译成dplyr式语法时,我遗漏了什么? 编辑2017:Dplyr已更新,因此可以使用更简单的解决方案。查看当前选定的答案。
我想使用<code>dplyr::mutate()</code>在数据帧中创建多个新列。应动态生成列名及其内容。 来自iris的示例数据: 我创建了一个函数,可以从<code>Petal中修改我的新列。宽度变量: 现在我创建一个循环来构建我的列: 然而,由于mutate认为varname是一个文字变量名,因此循环只创建一个新变量(称为varname),而不是四个(称为petal.2-petal.5
我试图计算在一个Tibble中源向量和比较向量之间的Jaccard相似度。 jaccard_sim中的所有值都为零。但是,如果我们运行类似这样的东西,我们得到第一个条目的正确的Jaccard相似度为0.2:
我想使用dplyr的mutate_at函数将一个函数应用于数据帧中的几个列,其中该函数输入它直接应用到的列以及数据帧中的另一列。 作为一个具体的例子,我希望改变以下数据帧 与调用类似 返回一个看起来像这样的数据框 所需的调用将类似于以下对的调用: 我知道这可以通过几种方式在base R中实现,但为了可读性、与数据库的接口等,我特别希望使用dplyr的mutate\u at函数来实现这一目标。 在d
我想使用在数据帧中创建多个新列。列名及其内容应动态生成。 来自IRIS的示例数据: 我创建了一个函数来从变量中更改新列: