Reputation: 174
I make a lot of frequency tables in R and was working on writing my own quick frequency table (qft) function when I ran into what I believe is a lexical scoping issue. Here is the version of my function that does not work
library("tidyverse")
data(mtcars)
qft_bad<-function(data,...){
ft<-data.frame(with(data, table(...)))
ft<-ft[ft$Freq!=0,]
return(ft)
}
tst_bad<-qft_bad(mtcars,cyl,gear)
You will notice that if you try to run qft_bad() that the Error "Error in table(...) : object 'cyl' not found" is produced. As a work around I wrote the following function which does produce the desired result but requires slightly different inputs.
qft_good<-function(data,...){
nmes<-c(...)
vars<-dplyr::select(data,...)
ft<-data.frame(table(vars))
ft<-ft[ft$Freq!=0,]
colnames(ft)[1:length(nmes)]<-nmes
return(ft)
}
tst_good<-qft_good(mtcars,"cyl","gear")
I'm guessing qft_bad() does not work because R tries to evaluate the arguments outside of the input dataset but am a little unclear as to the specifics of this problem (is there some issue with the with() function?).
As qft_good() works well enough for my purposes I am mainly asking this question for my own R Enlightenment. Can anyone provide a better explanation what's going on in my qft_bad() function, or create a version of the qft function that does not require you to list the variable names in quotes (as you must in qft_good())?
Upvotes: 0
Views: 52
Reputation: 3726
You can use quosures from rlang to capture the arguments in ...
then unquote splice them into a select
call:
library(tidyverse)
library(rlang)
qft <- function(data, ...){
args <- enquos(...)
vars <- select(data, !!!args)
ft <- data.frame(table(vars))
ft[ft$Freq != 0, ]
}
qft(mtcars, cyl, gear)
# cyl gear Freq
#1 4 3 1
#2 6 3 2
#3 8 3 12
#4 4 4 8
#5 6 4 4
#7 4 5 2
#8 6 5 1
#9 8 5 2
Upvotes: 1