如何在列上使用tidyeval进行突变? [英] How to use tidyeval on a column to mutate?

查看:224
本文介绍了如何在列上使用tidyeval进行突变?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很抱歉造成混乱,但是最终,我发布的第一个示例(在页面底部)并没有帮助我弄清楚tidyeval如何与mutate配合使用,因此我添加了一个新示例./p>

我想创建一个带有三个参数的函数:

  • 数据框
  • 要突变的列
  • 一个变量(来自数据框),用于替换要变异的值

例如,要将mpg中的值替换为carb中的值,我尝试了以下方法:

I tried this
colToX <- function(dt, ..., repl) {
  cols <- quos(...)
  repl <- quo(repl)
  mutate_at(dt, vars(!!!cols), funs(function(x) !!repl))
}

colToX(mtcars, mpg, repl = carb)

由于以下原因不起作用:

mutate_impl(.data,点)中的错误:不支持列mpg 类型功能

我的第一个示例(为此,@ MrFlick和@UseR都可以正常工作):

例如,下面的一个应mutate()将所有1分配给在...中传递的变量

colTo1 <- function(dt, ...) {
col <- quo(...)
mutate(mtcars, !!col := 1)
}

colTo1(mtcars, mpg)

错误:LHS必须是名称或字符串

最终,输出应与mutate(mtcars, mpg = 1)

相同

解决方案

@MrFlick的解决方案适用于单列情况,但是由于OP使用...作为参数,因此我认为OP也希望该函数能够分成多列.例如,以下操作将不起作用:

colTo1 <- function(dt, ...) {
  col <- quo_name(quo(...))
  mutate(dt, !!col := 1)
}

colTo1(mtcars, mpg, cyl)

inherits(x,"quosure")中的错误:找不到对象'cyl'

我们可以做的是使用quos代替quomutate_at代替mutate:

colTo1 <- function(dt, ...) {
  cols <- quos(...)
  mutate_at(dt, vars(!!!cols), function(x) x=1)
}

quos将每个参数从...转换为向量的向量.使用mutate_atvars语法并使用rlang中的!!!进行显式拼接,我们可以取消引用cols中的每个等价单,并在那些指定的列上进行变异.

现在这可以按预期工作了:

colTo1(mtcars, mpg, cyl)

结果:

   mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1    1   1 160.0 110 3.90 2.620 16.46  0  1    4    4
2    1   1 160.0 110 3.90 2.875 17.02  0  1    4    4
3    1   1 108.0  93 3.85 2.320 18.61  1  1    4    1
4    1   1 258.0 110 3.08 3.215 19.44  1  0    3    1
5    1   1 360.0 175 3.15 3.440 17.02  0  0    3    2
6    1   1 225.0 105 2.76 3.460 20.22  1  0    3    1
7    1   1 360.0 245 3.21 3.570 15.84  0  0    3    4
8    1   1 146.7  62 3.69 3.190 20.00  1  0    4    2
9    1   1 140.8  95 3.92 3.150 22.90  1  0    4    2
10   1   1 167.6 123 3.92 3.440 18.30  1  0    4    4
...

让"1"成为要传递给函数的另一个参数也很容易:

colToX <- function(dt, ..., X) {
  cols <- quos(...)
  mutate_at(dt, vars(!!!cols), function(x) x=X)
}

colToX(mtcars, mpg, cyl, X = 2)

编辑:OP更改了问题,要求X应该是同一数据框中的另一列.以下是我的新解决方案:

colToX <- function(dt, ..., X) {
  cols <- quos(...)
  X_quo <- enquo(X)
  mutate_at(dt, vars(!!!cols), funs(.data$`!!`(X_quo)))
}

colToX(mtcars, mpg, cyl, X = hp)

在这里,我正在使用funs函数创建对vars引用的每一列的函数调用列表. .data指的是mutate_at中的输入数据帧(在本例中为dt).我使用enquo将所谓的X转换为quosure,然后使用!!取消引用.

结果:

   mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1  110 110 160.0 110 3.90 2.620 16.46  0  1    4    4
2  110 110 160.0 110 3.90 2.875 17.02  0  1    4    4
3   93  93 108.0  93 3.85 2.320 18.61  1  1    4    1
4  110 110 258.0 110 3.08 3.215 19.44  1  0    3    1
5  175 175 360.0 175 3.15 3.440 17.02  0  0    3    2
6  105 105 225.0 105 2.76 3.460 20.22  1  0    3    1
7  245 245 360.0 245 3.21 3.570 15.84  0  0    3    4
8   62  62 146.7  62 3.69 3.190 20.00  1  0    4    2
9   95  95 140.8  95 3.92 3.150 22.90  1  0    4    2
10 123 123 167.6 123 3.92 3.440 18.30  1  0    4    4
...

I'm sorry for the confusion but eventually, the first example I posted (at the bottom of the page), did not help me to figure out how tidyeval works with mutate, so I'm adding a new example.

I would like to create a function that takes three args:

  • a dataframe
  • the column(s) to mutate
  • a variable (from the dataframe) to replace the values that are being mutated

For instance, to replace the values in mpg with the values from carb I tried this:

I tried this
colToX <- function(dt, ..., repl) {
  cols <- quos(...)
  repl <- quo(repl)
  mutate_at(dt, vars(!!!cols), funs(function(x) !!repl))
}

colToX(mtcars, mpg, repl = carb)

which doesn't work since:

Error in mutate_impl(.data, dots) : Column mpg is of unsupported type function

My first example (@MrFlick's and @UseR's both work fine for this):

For instance, the one below should mutate() assigning all 1 to the variable passed in ...

colTo1 <- function(dt, ...) {
col <- quo(...)
mutate(mtcars, !!col := 1)
}

colTo1(mtcars, mpg)

Error: LHS must be a name or string

Eventually, the output should be the same as mutate(mtcars, mpg = 1)

解决方案

@MrFlick's solution works for the one column case, but since OP used ... as an argument, I assume OP would also want the function to be able to take in multiple columns. For example, the following would not work:

colTo1 <- function(dt, ...) {
  col <- quo_name(quo(...))
  mutate(dt, !!col := 1)
}

colTo1(mtcars, mpg, cyl)

Error in inherits(x, "quosure") : object 'cyl' not found

What we can do is to use quos instead of quo and mutate_at instead of mutate:

colTo1 <- function(dt, ...) {
  cols <- quos(...)
  mutate_at(dt, vars(!!!cols), function(x) x=1)
}

quos converts each argument from ... into vector of quosures. Using mutate_at's vars syntax and explicit splicing with !!! from rlang, we can unquote each quosure in cols, and mutate on those specified columns.

Now this works as intended:

colTo1(mtcars, mpg, cyl)

Result:

   mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1    1   1 160.0 110 3.90 2.620 16.46  0  1    4    4
2    1   1 160.0 110 3.90 2.875 17.02  0  1    4    4
3    1   1 108.0  93 3.85 2.320 18.61  1  1    4    1
4    1   1 258.0 110 3.08 3.215 19.44  1  0    3    1
5    1   1 360.0 175 3.15 3.440 17.02  0  0    3    2
6    1   1 225.0 105 2.76 3.460 20.22  1  0    3    1
7    1   1 360.0 245 3.21 3.570 15.84  0  0    3    4
8    1   1 146.7  62 3.69 3.190 20.00  1  0    4    2
9    1   1 140.8  95 3.92 3.150 22.90  1  0    4    2
10   1   1 167.6 123 3.92 3.440 18.30  1  0    4    4
...

It's also easy enough to let "1" be another argument to be passed into the function:

colToX <- function(dt, ..., X) {
  cols <- quos(...)
  mutate_at(dt, vars(!!!cols), function(x) x=X)
}

colToX(mtcars, mpg, cyl, X = 2)

Edit: OP changed the question to require that X should be another column in the same dataframe. Below is my new solution:

colToX <- function(dt, ..., X) {
  cols <- quos(...)
  X_quo <- enquo(X)
  mutate_at(dt, vars(!!!cols), funs(.data$`!!`(X_quo)))
}

colToX(mtcars, mpg, cyl, X = hp)

Here, I am using the funs function to create a list of function calls to each column referenced from vars. .data refers to the input dataframe into mutate_at (in this case dt). I used enquo to convert what's called from X into a quosure and unquote it using !!.

Result:

   mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1  110 110 160.0 110 3.90 2.620 16.46  0  1    4    4
2  110 110 160.0 110 3.90 2.875 17.02  0  1    4    4
3   93  93 108.0  93 3.85 2.320 18.61  1  1    4    1
4  110 110 258.0 110 3.08 3.215 19.44  1  0    3    1
5  175 175 360.0 175 3.15 3.440 17.02  0  0    3    2
6  105 105 225.0 105 2.76 3.460 20.22  1  0    3    1
7  245 245 360.0 245 3.21 3.570 15.84  0  0    3    4
8   62  62 146.7  62 3.69 3.190 20.00  1  0    4    2
9   95  95 140.8  95 3.92 3.150 22.90  1  0    4    2
10 123 123 167.6 123 3.92 3.440 18.30  1  0    4    4
...

这篇关于如何在列上使用tidyeval进行突变?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆