1

I've been working on a problem involving tidy evaluation, which admittedly, I'm very new at. I have a simple function that makes contingency tables using summarize and pivot_wider from dplyr and tidyr, but I'm unable to pipe it into column_to_rowname from tibble:

library(tidyverse)

#Function to produce contingency table

countTable1 <- function(d,col1,col2){ #This function works correctly
  d %>% group_by({{col1}},{{col2}}) %>% summarize(n=n()) %>%
    pivot_wider(names_from={{col1}},values_from=n,values_fill=0)  
}

countTable2 <- function(d,col1,col2){ #This function fails
  d %>% group_by({{col1}},{{col2}}) %>% summarize(n=n()) %>%
    pivot_wider(names_from={{col1}},values_from=n,values_fill=0) %>% 
    column_to_rownames(var = as_label({{col2}})) #Should change col2 variable to rownames
}

Here's a test data set:

> #Test data
> d <- data.frame(c1=sample(letters[1:5],30,TRUE),c2=sample(letters[6:8],30,TRUE))
> countTable1(d,c1,c2) #Contingency table is fine, but c2 needs to be the rowname

# A tibble: 3 x 6
  c2        a     b     c     d     e
  <fct> <int> <int> <int> <int> <int>
1 f         3     3     2     1     2
2 g         4     0     3     2     4
3 h         0     2     0     2     2

> countTable1(d,c1,c2) %>% #Should behave like this:
+   column_to_rownames(var = 'c2')

  a b c d e
f 3 3 2 1 2
g 4 0 3 2 4
h 0 2 0 2 2

> countTable2(d,c1,c2) #This function fails
 Error in is_quosure(quo) : object 'c2' not found 

What is the proper way to convert a data variable to the name of the data variable? Clearly, the double-braced "curly-curly" operator isn't doing what I want it to. I couldn't find anything about this here, here, or here but I think I'm on the right track.

S. Robinson
  • 223
  • 1
  • 8

2 Answers2

3

In this case you would be better off explicitly using enquo for the variables that you need both as quosures and as string values. You can do

countTable2 <- function(d,col1,col2){ #This function fails
  col2 <- enquo(col2)
  d %>% group_by({{col1}},{{col2}}) %>% summarize(n=n()) %>%
    pivot_wider(names_from={{col1}}, values_from=n, values_fill=0) %>% 
    column_to_rownames(var = as_label(col2)) 
}
MrFlick
  • 195,160
  • 17
  • 277
  • 295
2

column_to_rownames requires string input. One way would be to use deparse + substitute.

Also I have changed group_by + summarise(n()) to count.

library(dplyr)

countTable2 <- function(d,col1,col2){ 

  col <- deparse(substitute(col2))
  d %>% 
    count({{col1}},{{col2}}) %>% 
    pivot_wider(names_from={{col1}},values_from=n,values_fill=0) %>%
    column_to_rownames(col) #Should change col2 variable to rownames
}

countTable2(d,c1,c2)
#  a b c d e
#f 5 3 2 0 4
#g 2 1 2 2 4
#h 0 4 0 0 1
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • 1
    This solution works, but I've discovered another weird quirk: this can cause problems if you try to use `deparse(substitute(x))` inside of the function instead of turning it into an extra variable as you do here. Hopefully this is useful to someone! – S. Robinson Dec 22 '21 at 21:39