问题
I am trying to search a database and then label the ouput with a name derived from the original search, "derived_name"
in the reproducible example below. I am using a dplyr
pipe %>%
, and I am having trouble with quasiquotation and/or non-standard evaluation. Specifically, using count_colname
, a character object derived from "derived_name"
, in the final top_n()
function fails to subset the dataframe.
search_name <- "derived_name"
set.seed(1)
letrs <- letters[rnorm(52, 13.5, 5)]
letrs_count.df <- letrs %>%
table() %>%
as.data.frame()
count_colname <- paste0(search_name, "_letr_count")
colnames(letrs_count.df) <- c("letr", count_colname)
letrs_top.df <- letrs_count.df %>%
top_n(5, count_colname)
identical(letrs_top.df, letrs_count.df)
# [1] TRUE
Based on this discussion I thought the code above would work. And this post lead me to try top_n_()
, which does not seem to exist.
I am studying vignette("programming")
which is a little over my head. This post led me to try the !! sym()
syntax, which works, but I have no idea why! Help understanding why the below code works would be much appreciated. Thanks.
colnames(letrs_count.df) <- c("letr", count_colname)
letrs_top.df <- letrs_count.df %>%
top_n(5, (!! sym(count_colname)))
letrs_top.df
# letr derived_name_letr_count
# 1 l 5
# 2 m 6
# 3 o 7
# 4 p 5
# 5 q 6
Additional confusing examples based on @lionel and @Tung's questions and comments below. What is confusing me here is that the help fils say that sym()
"take strings as input and turn them into symbols" and !!
"unquotes its argument". However, in the examples below, sym(count_colname)
appears to unquote to derived_name_letr_count
. I do not understand why the !!
is needed in !! sym(count_colname)
, since sym(count_colname)
and qq_show(!! sym(count_colname))
give the same value.
count_colname
# [1] "derived_name_letr_count"
sym(count_colname)
# derived_name_letr_count
qq_show(count_colname)
# count_colname
qq_show(sym(count_colname))
# sym(count_colname)
qq_show(!! sym(count_colname))
# derived_name_letr_count
qq_show(!! count_colname)
# "derived_name_letr_count"
回答1:
According to top_n
documentation (?top_n
), it doesn't support character
/string
input thus the 1st example didn't work. In your 2nd example, rlang::sym
converted the string to a variable name then !!
unquoted it so that it could be evaluated inside top_n
. Note: top_n and other dplyr verbs automatically quote their inputs.
Using rlang::qq_show
as suggested by @lionel, we can see it doesn't work because there is no count_colname
column in letrs_count.df
library(tidyverse)
set.seed(1)
letrs <- letters[rnorm(52, 13.5, 5)]
letrs_count.df <- letrs %>%
table() %>%
as.data.frame()
search_name <- "derived_name"
count_colname <- paste0(search_name, "_letr_count")
colnames(letrs_count.df) <- c("letr", count_colname)
letrs_count.df
#> letr derived_name_letr_count
#> 1 b 1
#> 2 c 1
#> 3 f 2
...
rlang::qq_show(top_n(letrs_count.df, 5, count_colname))
#> top_n(letrs_count.df, 5, count_colname)
sym
& !!
create the right column name existing in letrs_count.df
rlang::qq_show(top_n(letrs_count.df, 5, !! sym(count_colname)))
#> top_n(letrs_count.df, 5, derived_name_letr_count)
letrs_count.df %>%
top_n(5, !! sym(count_colname))
#> letr derived_name_letr_count
#> 1 l 5
#> 2 m 6
#> 3 o 7
#> 4 p 5
#> 5 q 6
top_n(x, n, wt)
Arguments:
x
: atbl()
to filtern
: number of rows to return. Ifx
is grouped, this is the number of rows per group. Will include more thann
rows if there are ties. Ifn
is positive, selects the topn
rows. If negative, selects the bottomn
rows.wt
: (Optional). The variable to use for ordering. If not specified, defaults to the last variable in thetbl
. This argument is automatically quoted and later evaluated in the context of the data frame. It supports unquoting. Seevignette("programming")
for an introduction to these concepts.
See also these answers: 1st, 2nd, 3rd
回答2:
So, I've realized that what I was struggling with in this question (and many other probelms) is not really quasiquotation and/or non-standard evaluation, but rather converting character strings into object names. Here is my new solution:
letrs_top.df <- letrs_count.df %>%
top_n(5, get(count_colname))
来源:https://stackoverflow.com/questions/51738267/non-standard-evaluation-and-quasiquotation-in-dplyr-not-working-as-naively-e