You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于dplyr中符号解引用及!!/!!!运算符用法的技术疑问

Understanding !! and !!! in dplyr::select(): Beyond Column Selection

Great question—these "bang" operators are easy to confuse at first, but they’re tied to a core part of how dplyr works under the hood: non-standard evaluation (NSE). Let’s break down what they do, using your example as a starting point.

First: Why Do We Need These Operators?

Most dplyr functions (like select(), mutate()) use NSE, which lets you write column names directly without quotes—e.g., select(mtcars, cyl, am) instead of select(mtcars, "cyl", "am"). But this creates a problem when your column names (or renaming rules) are stored in a variable: if you just write select(mtcars, vars), dplyr will look for a column named vars (which doesn’t exist in mtcars), not the values inside vars.

That’s where !! and !!! come in: they tell dplyr, "Don’t treat this variable as a column name—take its contents and use those instead."

What !! (Bang-Bang) Does

!! is a single-value injection operator. It takes a single object (like your named vector vars <- c(var1 = "cyl", var2 = "am")) and inserts it into the dplyr function call as-is.

In your example:

library(dplyr)
vars <- c(var1 = "cyl", var2 = "am")
select(mtcars, !!vars)

This is equivalent to writing:

select(mtcars, var1 = cyl, var2 = am)

The !! tells dplyr: "Take the named vector vars, and treat each key-value pair as a new_name = old_column rule." It’s not just selecting columns—it’s dynamically renaming them at the same time.

Under the hood, !! uses rlang’s expression injection to rewrite the function call before dplyr processes it. It replaces !!vars with the actual contents of vars during the "quoting" phase of the NSE workflow.

What !!! (Bang-Bang-Bang) Does

!!! is a multi-value splat operator. It takes a collection (vector, list, etc.) and splits it into individual arguments for the function.

For example, if you have an unnamed vector:

vars <- c("cyl", "am")
select(mtcars, !!!vars)

This is exactly equivalent to:

select(mtcars, cyl, am)

The !!! splits the vector into two separate column name arguments.

With a named vector (like your original example), !!! will also split each key-value pair into individual new_name = old_column arguments:

vars <- c(var1 = "cyl", var2 = "am")
select(mtcars, !!!vars)

This produces the same result as !!vars here, because select() accepts multiple renaming pairs as arguments. The difference becomes clearer when working with lists or more complex objects: !! injects the whole object as one argument, while !!! breaks it into many.

Beyond select(): General Use Cases

These operators aren’t limited to select()—they work across all dplyr functions that use NSE. For example:

  • Dynamically creating columns in mutate():
    new_cols <- list(new_cyl = ~cyl * 2, new_mpg = ~mpg + 5)
    mtcars %>% mutate(!!!new_cols)
    
  • Dynamically filtering with filter():
    filter_expr <- quote(cyl == 6)
    mtcars %>% filter(!!filter_expr)
    

Key Takeaway

!! and !!! aren’t just tools for selecting columns—they’re ways to escape dplyr’s default NSE behavior and inject dynamic content into your function calls. Their power comes from letting you build flexible, reusable code where your operations are controlled by variables, not hardcoded values.

内容的提问来源于stack exchange,提问作者Slayer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:02:45