1

I am having difficulties in mixing SE and NSE dplyr evaluation in a function. I have a dataset for which I want to divide each column based on the number of occurrences on a different column.

Let me write a small function with the functionality I am after

func <- function(param) {
 mtcars %>%
 group_by(cyl) %>%
 summarise_each(funs_(lazyeval::interp(~sum(.))/lazyeval::interp(~sum(var == 
 0), var = as.name(param))))
 }

Function is to be used such as func(am) or func(vs)

I have tried various alternatives to that function, but none is working.

What I am missing?

Jordi Vidal
  • 439
  • 1
  • 6
  • 10

1 Answers1

2

In this case it's funs that needs to be used in its standard evaluation version (funs_). Also, the whole formula goes under one call to interp. For example:

func <- function(param, data=mtcars) {
  data %>%
    group_by(cyl) %>%
    summarise_each(funs_(lazyeval::interp(~sum(.)/sum(.[var==0]), var = as.name(param))))
}

func("vs")
    cyl      mpg     disp       hp      drat        wt      qsec    vs    am  gear  carb
1     4 11.28077 9.613466 9.989011 10.108352 11.749065 12.605389   Inf   Inf   Inf   Inf
2     6  2.23987 2.759570 2.167089  2.197898  2.640048  2.569212   Inf   Inf   Inf   Inf
3     8  1.00000 1.000000 1.000000  1.000000  1.000000  1.000000   NaN    NA    NA    NA

Or, a more general function:

func <- function(param, param.subset, groupvar, data) {
  data %>%
    group_by_(groupvar) %>%
    summarise_each(funs_(lazyeval::interp(
      ~if(is.numeric(.)) {
        sum(.[var==param.subset])/sum(.)
      } else {
        length(unique(.[var==param.subset]))
      }, var = as.name(param))))
}

func(param="gender", param.subset="Girl", groupvar="grade", data=vcd::JointSports)
   grade      Freq opinion  year gender
1    1st 0.5866477       5     2      1
2    3rd 0.6137566       5     2      1

I still feel like I don't really "get" standard evaluation with dplyr and would be interested in whether there are better approaches than the code above.

eipi10
  • 91,525
  • 24
  • 209
  • 285