Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

recode_factor does not handle !!! #3390

Closed
dan87134 opened this issue Mar 3, 2018 · 4 comments
Closed

recode_factor does not handle !!! #3390

dan87134 opened this issue Mar 3, 2018 · 4 comments
Labels
feature a feature request or enhancement

Comments

@dan87134
Copy link

dan87134 commented Mar 3, 2018

A code snippet like this

dplyr::recode_factor(x, !!! layer_key)

produces an error that says !level_key is an invalid argument type

This is the result of a question on https://community.rstudio.com/t/using-recode-factor-with-quasi-quotation/5761/5

Here is a repro

library(magrittr)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
set.seed(100)
x <- sample(head(LETTERS, 3), 10, replace = TRUE) %>% factor
x
#>  [1] A A B A B B C B B A
#> Levels: A B C
level_key <- list("Be", "Cool", "Amigo") %>% set_names(c("B", "C", "A"))    # set factor re-level 
level_key2 <- list(B = "Be", C = "Cool", A = "Amigo")

dplyr::recode_factor(x, !!!level_key)
#> Error in !level_key: invalid argument type

Created on 2018-03-03 by the reprex package (v0.2.0).

The problem is the use of c(...) inside of rcode_factor. Here is my analysis of the problem.

The problem is buried inside of recode_factor. It is that only functions that are implemented to use quosures can properly interpret !!!

Here is where the problem is in recode_factor:

dplyr:::recode_factor
#> function (.x, ..., .default = NULL, .missing = NULL, .ordered = FALSE) 
#> {
#>     recoded <- recode(.x, ..., .default = .default, .missing = .missing)
# ----------------------------The . problem is with c() ----
#>     all_levels <- unique(c(..., recode_default(.x, .default, 
#>         recoded), .missing))
#>     recoded_levels <- if (is.factor(recoded)) 
#>         levels(recoded)
#>     else unique(recoded)
#>     levels <- intersect(all_levels, recoded_levels)
#>     factor(recoded, levels, ordered = .ordered)
#> }
#> <environment: namespace:dplyr>

Created on 2018-03-03 by the reprex package (v0.2.0).

The problem is in the Combine, c(), function. Although in !!! layer_key !!! looks like an operator or in !!!(layer_key) it looks like a function it is neither.

It depends on the function getting the !!! layer_key in an ... argument to do something like enquo(...) so that standard evaluation is bypassed. It is enquo(or one of it's friends) that interprets !!! to turn a list into individual dot arguments.

But c() is a primitive function so it just does standard evaluation of !!! level_key which, in effect, produces a syntax kind of error.

Here is an example of a function that tries to use !!! with c()

suppressPackageStartupMessages(library(tidyverse))
f2 <- function(...) {
    c(...)
}
level_key <- list("Be", "Cool", "Amigo") %>% set_names(c("B", "C", "A"))    # set factor re-level 

f2(!!! level_key)
#> Error in !level_key: invalid argument type

Created on 2018-03-03 by the reprex package (v0.2.0).

I don't see a workaround for this.

@batpigandme
Copy link
Contributor

Just adding an example of what we would expect, here:

Expect:

suppressPackageStartupMessages(library(tidyverse))
set.seed(100)
x <- sample(head(LETTERS, 3), 10, replace = TRUE) %>% 
  factor
recode_factor(x, B = "Be", C = "Cool", A = "Amigo")
#>  [1] Amigo Amigo Be    Amigo Be    Be    Cool  Be    Be    Amigo
#> Levels: Be Cool Amigo

Get:

level_key <- list(B = "Be", C = "Cool", A = "Amigo")
recode_factor(x, !!!level_key)
#> Error in !level_key: invalid argument type

Created on 2018-03-03 by the reprex package (v0.2.0).

@cderv
Copy link
Contributor

cderv commented Mar 3, 2018

for helping with cross reference, this issue is related to #3388 that was asked before and redirected to community.rstudio.com

@krlmlr krlmlr added feature a feature request or enhancement data frame labels Mar 12, 2018
@batpigandme
Copy link
Contributor

batpigandme commented Mar 25, 2018

@cderv yeah, I think community served its purpose well— turned out it was a bug, and thus landed back here! 😁

Related: #3218

Oddly enough, it works with dplry::recode.

suppressPackageStartupMessages(library(tidyverse))
set.seed(100)
x <- sample(head(LETTERS, 3), 10, replace = TRUE) %>% 
  factor

level_key <- list(B = "Be", C = "Cool", A = "Amigo")
dplyr::recode(x, !!! level_key)
#>  [1] Amigo Amigo Be    Amigo Be    Be    Cool  Be    Be    Amigo
#> Levels: Amigo Be Cool

Created on 2018-03-25 by the reprex package (v0.2.0).

@lock
Copy link

lock bot commented Sep 22, 2018

This old issue has been automatically locked. If you believe you have found a related problem, please file a new issue (with reprex) and link to this issue. https://reprex.tidyverse.org/

@lock lock bot locked and limited conversation to collaborators Sep 22, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature a feature request or enhancement
Projects
None yet
Development

No branches or pull requests

4 participants