解析公式
Parsing a formula
我有以下函数,gigl
,我试图在其中捕获 |
左右两侧的变量。目前我的代码只捕获准确命名为 s
或 n
的变量。
我如何概括以下内容以评估任何变量而不考虑名称?
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)
这是一些玩具数据
library(tidyverse)
df <- tribble(
~n, ~s,
10, 6,
8, 7,
6, 5
)
下面应该像上面一样工作,但目前不工作
df2 <- tribble(
~total, ~positive,
10, 6,
8, 7,
6, 5
)
fit <- gigl(total | positive ~ 1 , data=df2)
输出应该是
total positive
[1,] 10 6
[2,] 8 7
[3,] 6 5
这是一种方法。但是,有很多方法可以破坏此实现,如果输入公式不完全符合您期望的格式,您需要考虑要做什么。例如,我添加了一个小检查以确保左侧确实有一个 |
。
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)
}
检查它是否有效:
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
或者您可以使用 !!!
和 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
由 reprex package (v0.2.0) 创建于 2018-02-19。
我有以下函数,gigl
,我试图在其中捕获 |
左右两侧的变量。目前我的代码只捕获准确命名为 s
或 n
的变量。
我如何概括以下内容以评估任何变量而不考虑名称?
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)
这是一些玩具数据
library(tidyverse)
df <- tribble(
~n, ~s,
10, 6,
8, 7,
6, 5
)
下面应该像上面一样工作,但目前不工作
df2 <- tribble(
~total, ~positive,
10, 6,
8, 7,
6, 5
)
fit <- gigl(total | positive ~ 1 , data=df2)
输出应该是
total positive
[1,] 10 6
[2,] 8 7
[3,] 6 5
这是一种方法。但是,有很多方法可以破坏此实现,如果输入公式不完全符合您期望的格式,您需要考虑要做什么。例如,我添加了一个小检查以确保左侧确实有一个 |
。
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)
}
检查它是否有效:
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
或者您可以使用 !!!
和 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
由 reprex package (v0.2.0) 创建于 2018-02-19。