Tobias Dekker
Tobias Dekker

Reputation: 1030

Combining standard and non standard evaluation in dplyr

I am trying to perform a task in dplyr in which non-standard and standard evaluation should be combined, but I could not find a convenient solution. I want to reorder a level based on another column in the data.frame (needed for a visualisation):

df <- data.frame(A = c(1,2,5,4), B = c("A", "B", "C","D"))
levels(df$B)
df2 <- df %>% mutate(B  = factor(B, levels = unique(B)[order(A, decreasing = FALSE)]))
levels(df$B)

So far, so good. But now I want to do exactly the same task but B is the input of a function:

ReorderFactor <- function(column_name){
    df2 <- df %>% mutate(column_name  = factor(column_name, levels = unique(column_name)[order(A, decreasing = FALSE)]))
    return(df2)
}
ReorderFactor(column_name = "B")

So I want to combine both standard and non-standard evaluation. I am searching for a dplyr approach.

Upvotes: 0

Views: 313

Answers (2)

Romain Francois
Romain Francois

Reputation: 17632

You can use mutate_at and then refer to the variable being mutated as .

ReorderFactor <- function(column_name){
  df2 <- df %>% 
    mutate_at(column_name, funs(factor(., levels = unique(.)[order(A, decreasing = FALSE)])) ) 
  return(df2)
}

Upvotes: 2

akrun
akrun

Reputation: 886938

We can use the quosure from the devel version of dplyr (soon to be released 0.6.0)

ReorderFactor <- function(dat, column_name){
          column_name <- enquo(column_name)
          nm1 <- quo_name(column_name)
          dat %>%
              mutate(UQ(nm1) := factor(UQ(column_name), 
                   levels = unique(UQ(column_name))[order(A, decreasing = FALSE)]))

}

dfN <- ReorderFactor(df, B)
identical(df2, dfN)
#[1] TRUE

Here, the enquo takes the input argument and converts to a quosure which is evaluated within the mutate/summarise etc by unquoting(UQ). Note that we are able to assign (:=) the values on the lhs by unquoting the string ('nm1')

NOTE: Here, we included 'dat' as another argument in case the function needs to be applied on a different dataset

Upvotes: 2

Related Questions