I have the following function, gigl
, where I am trying to capture the variables on the left and right of |
. Currently my code only captures the variables if it is named exactly s
or n
.
How can I generalize the following to evaluate any variable regardless of the name?
gigl <- function(form,data){
s <- rlang::f_lhs(f_lhs(form))
n <- rlang::f_rhs(f_lhs(form))
s <- eval_tidy(data$s) # don't like that I have to use the same name as inputed. Make more general.
n <- eval_tidy(data$n) # don't like that I have to use the same name as inputed. Make more general.
output <- tibble(n,s) %>% data.matrix()
output
}
fit <- gigl(s | n ~ 1 , data=df)
Here is some toy data
library(tidyverse)
df <- tribble(
~n, ~s,
10, 6,
8, 7,
6, 5
)
The following should work as above, but is currently not working
df2 <- tribble(
~total, ~positive,
10, 6,
8, 7,
6, 5
)
fit <- gigl(total | positive ~ 1 , data=df2)
The output should be
total positive
[1,] 10 6
[2,] 8 7
[3,] 6 5
Here's one way to do it. However, there's a lot of ways to break this implementation, and you would need to think about what you want to do if the input formula is not exactly in the format you expect. For example, I added a little check to make sure there actually is a |
on the left hand side.
library(tidyverse)
library(rlang)
gigl <- function(form, data) {
# Get the left hand side expression from the formula
lhs <- f_lhs(form)
# Check that the lhs actually has a `|`
stopifnot(is.call(lhs), as_string(lhs[[1]]) == "|")
# Get the expressions from either side of `|` in a list of length 2
exprs <- as.list(lhs[-1])
# Create names from them
names <- map(exprs, expr_name)
# Evaluate them to get the values
values <- map(exprs, eval_tidy, data)
# Construct the data frame
df <- invoke(data.frame, set_names(values, names))
# Return
data.matrix(df)
}
Check that it works:
df2 <- tribble(
~total, ~positive,
10, 6,
8, 7,
6, 5
)
gigl(total | positive ~ 1 , data = df2)
#> total positive
#> [1,] 10 6
#> [2,] 8 7
#> [3,] 6 5
Or you could have a more succint solution using !!!
with select
:
gigl2 <- function(form, data) {
lhs <- f_lhs(form)
stopifnot(is.call(lhs))
stopifnot(as_string(lhs[[1]]) == "|")
exprs <- as.list(lhs[-1])
df <- select(data, !!!exprs)
data.matrix(df)
}
gigl2(total | positive ~ 1 , data = df2)
#> total positive
#> [1,] 10 6
#> [2,] 8 7
#> [3,] 6 5
Created on 2018-02-19 by the reprex package (v0.2.0).