EVOLUTION-MANAGER
Edit File: topic-data-mask.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>R: What is data-masking and why do I need {{?</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="stylesheet" type="text/css" href="R.css" /> </head><body> <table width="100%" summary="page for topic-data-mask {rlang}"><tr><td>topic-data-mask {rlang}</td><td style="text-align: right;">R Documentation</td></tr></table> <h2>What is data-masking and why do I need <code style="white-space: pre;">{{</code>?</h2> <h3>Description</h3> <p>Data-masking is a distinctive feature of R whereby programming is performed directly on a data set, with columns defined as normal objects. </p> <div class="sourceCode r"><pre># Unmasked programming mean(mtcars$cyl + mtcars$am) #> [1] 6.59375 # Referring to columns is an error - Where is the data? mean(cyl + am) #> Error in mean(cyl + am): object 'cyl' not found # Data-masking with(mtcars, mean(cyl + am)) #> [1] 6.59375 </pre></div> <p>While data-masking makes it easy to program interactively with data frames, it makes it harder to create functions. Passing data-masked arguments to functions requires injection with the embracing operator <code><a href="embrace-operator.html">{{</a></code> or, in more complex cases, the injection operator <code><a href="injection-operator.html">!!</a></code>. </p> <h3>Why does data-masking require embracing and injection?</h3> <p>Injection (also known as quasiquotation) is a metaprogramming feature that allows you to modify parts of a program. This is needed because under the hood data-masking works by <a href="topic-defuse.html">defusing</a> R code to prevent its immediate evaluation. The defused code is resumed later on in a context where data frame columns are defined. </p> <p>Let's see what happens when we pass arguments to a data-masking function like <code>summarise()</code> in the normal way: </p> <div class="sourceCode r"><pre>my_mean <- function(data, var1, var2) { dplyr::summarise(data, mean(var1 + var2)) } my_mean(mtcars, cyl, am) #> Error in `dplyr::summarise()`: #> ! Can't compute `..1 = mean(var1 + var2)`. #> Caused by error in `mean()`: #> ! object 'cyl' not found </pre></div> <p>The problem here is that <code>summarise()</code> defuses the R code it was supplied, i.e. <code>mean(var1 + var2)</code>. Instead we want it to see <code>mean(cyl + am)</code>. This is why we need injection, we need to modify that piece of code by injecting the code supplied to the function in place of <code>var1</code> and <code>var2</code>. </p> <p>To inject a function argument in data-masked context, just embrace it with <code style="white-space: pre;">{{</code>: </p> <div class="sourceCode r"><pre>my_mean <- function(data, var1, var2) { dplyr::summarise(data, mean({{ var1 }} + {{ var2 }})) } my_mean(mtcars, cyl, am) #> # A tibble: 1 x 1 #> `mean(cyl + am)` #> <dbl> #> 1 6.59 </pre></div> <p>See <a href="topic-data-mask-programming.html">Data mask programming patterns</a> to learn more about creating functions around data-masking functions. </p> <h3>What does "masking" mean?</h3> <p>In normal R programming objects are defined in the current environment, for instance in the global environment or the environment of a function. </p> <div class="sourceCode r"><pre>factor <- 1000 # Can now use `factor` in computations mean(mtcars$cyl * factor) #> [1] 6187.5 </pre></div> <p>This environment also contains all functions currently in scope. In a script this includes the functions attached with <code>library()</code> calls; in a package, the functions imported from other packages. If evaluation was performed only in the data frame, we'd lose track of these objects and functions necessary to perform computations. </p> <p>To keep these objects and functions in scope, the data frame is inserted at the bottom of the current chain of environments. It comes first and has precedence over the user environment. In other words, it <em>masks</em> the user environment. </p> <p>Since masking blends the data and the user environment by giving priority to the former, R can sometimes use a data frame column when you really intended to use a local object. </p> <div class="sourceCode r"><pre># Defining an env-variable cyl <- 1000 # Referring to a data-variable dplyr::summarise(mtcars, mean(cyl)) #> # A tibble: 1 x 1 #> `mean(cyl)` #> <dbl> #> 1 6.19 </pre></div> <p>The tidy eval framework provides <a href="dot-data.html">pronouns</a> to help disambiguate between the mask and user contexts. It is often a good idea to use these pronouns in production code. </p> <div class="sourceCode r"><pre>cyl <- 1000 mtcars %>% dplyr::summarise( mean_data = mean(.data$cyl), mean_env = mean(.env$cyl) ) #> # A tibble: 1 x 2 #> mean_data mean_env #> <dbl> <dbl> #> 1 6.19 1000 </pre></div> <p>Read more about this in <a href="topic-data-mask-ambiguity.html">The data mask ambiguity</a>. </p> <h3>How does data-masking work?</h3> <p>Data-masking relies on three language features: </p> <ul> <li> <p><a href="topic-defuse.html">Argument defusal</a> with <code><a href="../../base/html/substitute.html">substitute()</a></code> (base R) or <code><a href="enquo.html">enquo()</a></code>, <code><a href="enquo.html">enquos()</a></code>, and <code><a href="embrace-operator.html">{{</a></code> (rlang). R code is defused so it can be evaluated later on in a special environment enriched with data. </p> </li> <li><p> First class environments. Environments are a special type of list-like object in which defused R code can be evaluated. The named elements in an environment define objects. Lists and data frames can be transformed to environments: </p> <div class="sourceCode r"><pre>as.environment(mtcars) #> <environment: 0x7febb17e3468> </pre></div> </li> <li><p> Explicit evaluation with <code><a href="../../base/html/eval.html">eval()</a></code> (base) or <code><a href="eval_tidy.html">eval_tidy()</a></code> (rlang). When R code is defused, evaluation is interrupted. It can be resumed later on with <code><a href="../../base/html/eval.html">eval()</a></code>: </p> <div class="sourceCode r"><pre>expr(1 + 1) #> 1 + 1 eval(expr(1 + 1)) #> [1] 2 </pre></div> <p>By default <code>eval()</code> and <code>eval_tidy()</code> evaluate in the current environment. </p> <div class="sourceCode r"><pre>code <- expr(mean(cyl + am)) eval(code) #> Error in mean(cyl + am): object 'am' not found </pre></div> <p>You can supply an optional list or data frame that will be converted to an environment. </p> <div class="sourceCode r"><pre>eval(code, mtcars) #> [1] 6.59375 </pre></div> <p>Evaluation of defused code then occurs in the context of a data mask. </p> </li></ul> <h3>History</h3> <p>The tidyverse embraced the data-masking approach in packages like ggplot2 and dplyr and eventually developed its own programming framework in the rlang package. None of this would have been possible without the following landmark developments from S and R authors. </p> <ul> <li><p> The S language introduced data scopes with <code><a href="../../base/html/attach.html">attach()</a></code> (Becker, Chambers and Wilks, The New S Language, 1988). </p> </li> <li><p> The S language introduced data-masked formulas in modelling functions (Chambers and Hastie, 1993). </p> </li> <li><p> Peter Dalgaard (R team) wrote the frametools package in 1997. It was later included in R as <code><a href="../../base/html/transform.html">base::transform()</a></code> and <code><a href="../../base/html/subset.html">base::subset()</a></code>. This API is an important source of inspiration for the dplyr package. It was also the first apparition of <em>selections</em>, a variant of data-masking extended and codified later on in the <a href="https://tidyselect.r-lib.org/articles/syntax.html">tidyselect package</a>. </p> </li> <li><p> In 2000 Luke Tierney (R team) <a href="https://github.com/wch/r-source/commit/a945ac8e">changed formulas</a> to keep track of their original environments. This change published in R 1.1.0 was a crucial step towards hygienic data masking, i.e. the proper resolution of symbols in their original environments. Quosures were inspired by the environment-tracking mechanism of formulas. </p> </li> <li><p> Luke introduced <code><a href="../../base/html/with.html">base::with()</a></code> in 2001. </p> </li> <li><p> In 2006 the <a href="https://r-datatable.com">data.table package</a> included data-masking and selections in the <code>i</code> and <code>j</code> arguments of the <code>[</code> method of a data frame. </p> </li> <li><p> The <a href="https://dplyr.tidyverse.org/">dplyr package</a> was published in 2014. </p> </li> <li><p> The rlang package developed tidy eval in 2017 as the data-masking framework of the tidyverse. It introduced the notions of <a href="topic-quosure.html">quosure</a>, <a href="topic-inject.html">implicit injection</a> with <code style="white-space: pre;">!!</code> and <code style="white-space: pre;">!!!</code>, and <a href="dot-data.html">data pronouns</a>. </p> </li> <li><p> In 2019, injection with <code style="white-space: pre;">{{</code> was introduced in <a href="https://www.tidyverse.org/blog/2019/06/rlang-0-4-0/">rlang 0.4.0</a> to simplify the defuse-and-inject pattern. This operator allows R programmers to transport data-masked arguments across functions more intuitively and with minimal boilerplate. </p> </li></ul> <h3>See also</h3> <ul> <li> <p><a href="topic-data-mask-programming.html">Data mask programming patterns</a> </p> </li> <li> <p><a href="topic-defuse.html">Defusing R expressions</a> </p> </li></ul> <hr /><div style="text-align: center;">[Package <em>rlang</em> version 1.0.6 <a href="00Index.html">Index</a>]</div> </body></html>