如何编写使用 broom、dplyr 和 lm 的函数?

how to write a function that uses broom, dplyr and lm?

考虑这个非常简单的例子

library(dplyr)
library(broom)

dataframe <- data_frame(id = c(1,2,3,4,5,6),
                        group = c(1,1,1,2,2,2),
                        value = c(200,400,120,300,100,100))

# A tibble: 6 x 3
     id group value
  <dbl> <dbl> <dbl>
1     1     1   200
2     2     1   400
3     3     1   120
4     4     2   300
5     5     2   100
6     6     2   100

这里我想编写一个函数,输出 value 均值的置信度估计上限。也就是说,

get_ci_high <- function(data, myvar){
  confint_tidy(lm(data = data, myvar ~ 1)) %>% pull(conf.high)
}

现在,这很容易实现

confint_tidy(lm(data = dataframe, value ~ 1)) %>% pull(conf.high)
[1] 332.9999

这也有效(注意 group_by 之后的调用)

dataframe %>% group_by(group) %>% mutate(dealwithit = get_ci_high(., value))
# A tibble: 6 x 4
# Groups:   group [2]
     id group value dealwithit
  <dbl> <dbl> <dbl>      <dbl>
1     1     1   200   598.2674
2     2     1   400   598.2674
3     3     1   120   598.2674
4     4     2   300   453.5102
5     5     2   100   453.5102
6     6     2   100   453.5102

效果很好

mindblow <- function(data, groupvar, outputvar){
  quo_groupvar <- enquo(groupvar)
  quo_outputvar <- enquo(outputvar)

  data %>% group_by(!!quo_groupvar) %>% 
    summarize(output =  get_ci_high(., !!quo_outputvar))%>% 
    ungroup()

}

> mindblow(dataframe, groupvar = group, outputvar = value)
# A tibble: 2 x 2
  group   output
  <dbl>    <dbl>
1     1 598.2674
2     2 453.5102

...但这失败

get_ci_high(dataframe, value)
 Error in eval(expr, envir, enclos) : object 'value' not found 

我不明白这里有什么问题。我真的需要一个适用于上述四种情况的解决方案。

有什么想法吗? 非常感谢!!

原因是当你传递value参数时,你希望R在公式中使用它的名称 "value",而不是值变量(不存在)。

一种解决方案是使用 substitute() (non-standard evaluation) 提取名称,并使用 as.formula:

创建公式
get_ci_high <- function(data, myvar) {
  col_name <- as.character(substitute(myvar))
  fmla <- as.formula(paste(col_name, "~ 1"))

  confint_tidy(lm(data = data, fmla)) %>% pull(conf.high)
}

get_ci_high(dataframe, value)

但是,我强烈建议将 公式 value ~ 1 作为第二个参数传递。这对于执行其他线性模型(当您也有预测变量时)既简单又灵活。

get_ci_high <- function(data, fmla) {      
  confint_tidy(lm(data = data, fmla)) %>% pull(conf.high)
}

get_ci_high(dataframe, value ~ 1)