用“%>%”将lsmeans写入函数

时间:2019-08-28 06:59:01

标签: r function rlang lsmeans

以“ mpg”数据为例, 我编写了一些代码以非函数格式调用lsmeans函数,输出对我来说很好(如下所示)。

我尝试将代码修改为函数格式以生成相同的输出,但是在我编写的函数中无法识别数据的列。

我的函数报告的错误是:

Error in eval(predvars, data, env) : object 'cty' not found

我的代码格式不正确:

library(rlang)
library(tidyverse)
library(dplyr)
library(multcompView)
library(lsmeans)


model = lm(cty ~ drv + class + drv:class,data=mpg)
anova(model)

marginal = lsmeans(model,~drv:class)

Pletters = multcomp::cld(marginal,
          alpha=0.05,
          Letters=letters,
          adjust="tukey")
Pletters$.group=gsub(" ", "", Pletters$.group)
Pletters

我编写的对我不起作用的功能代码:

library(rlang)
library(tidyverse)
library(dplyr)
library(multcompView)
library(lsmeans)

P_letters<-function(data, y, groupby, subgroupby){

model = lm(y ~ groupby + subgroupby + groupby:subgroupby,data=data)
anova(model)

marginal = lsmeans(model,~groupby:subgroupby)

Pletters = multcomp::cld(marginal,
          alpha=0.05,
          Letters=letters,
          adjust="tukey")
Pletters$.group=gsub(" ", "", Pletters$.group)
Pletters
}

使用“ mpg”数据调用该函数:

result<-mpg %>%  
P_letters(y=cty, groupby=drv, subgroupby=class)
result

非功能格式代码的输出:

nalysis of Variance Table

Response: cty
           Df  Sum Sq Mean Sq  F value Pr(>F)    
drv         2 1878.81  939.41 136.6198 <2e-16 ***
class       6  804.78  134.13  19.5069 <2e-16 ***
drv:class   3   10.26    3.42   0.4974 0.6844    
Residuals 222 1526.49    6.88                    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
 drv class      lsmean    SE  df lower.CL upper.CL .group
 r   suv          12.0 0.791 222     9.58     14.4 a     
 4   pickup       13.0 0.456 222    11.60     14.4 a     
 4   suv          13.8 0.367 222    12.70     14.9 a     
 r   2seater      15.4 1.173 222    11.80     19.0 ab    
 f   minivan      15.8 0.791 222    13.39     18.2 ab    
 r   subcompact   15.9 0.874 222    13.21     18.6 ab    
 4   midsize      16.0 1.514 222    11.36     20.6 abc   
 4   compact      18.0 0.757 222    15.68     20.3 bc    
 f   midsize      19.0 0.425 222    17.67     20.3 bc    
 4   subcompact   19.5 1.311 222    15.48     23.5 bcd   
 f   compact      20.9 0.443 222    19.50     22.2 cd    
 f   subcompact   22.4 0.559 222    20.65     24.1 d     
 4   2seater    nonEst    NA  NA       NA       NA       
 f   2seater    nonEst    NA  NA       NA       NA       
 r   compact    nonEst    NA  NA       NA       NA       
 r   midsize    nonEst    NA  NA       NA       NA       
 4   minivan    nonEst    NA  NA       NA       NA       
 r   minivan    nonEst    NA  NA       NA       NA       
 f   pickup     nonEst    NA  NA       NA       NA       
 r   pickup     nonEst    NA  NA       NA       NA       
 f   suv        nonEst    NA  NA       NA       NA       

Confidence level used: 0.95 
Conf-level adjustment: sidak method for 21 estimates 
P value adjustment: tukey method for comparing a family of 21 estimates 
significance level used: alpha = 0.05 

我的函数格式代码错误:

Error in eval(predvars, data, env) : object 'cty' not found

1 个答案:

答案 0 :(得分:0)

某些R函数直接对用户编写的表达式进行操作,而不是对其求值。这是一个相当高级的概念,称为非标准评估(NSE),您可以在最近的tidy evaluation guide中进一步了解它。作为NSE的一个非常简短的示例,请考虑library()函数:

library("tidyverse")              # Works

a <- "tidyverse"
library( a )
# Error in library(a) : there is no package called ‘a’

如果library()使用标准评估规则,则表达式a会被评估为产生值"tidyverse",然后将其传递给library()。但是,由于使用NSE,该函数直接与a一起使用,而不是对其求值。

您要使用的功能属于同一伞下,需要特殊处理才能处理用户提供的表达式。 rlang软件包提供了several mechanisms for this。特别是,我们将使用1)ensym()捕获提供给函数的变量名; 2)expr()组成一个未计算的表达式; 3)!!运算符强制执行表达式求值。

P_letters <- function(data, y, groupby, subgroupby) {
  ## Compose a formula expression using user-supplied variable names
  frml <- expr( !!ensym(y) ~ !!ensym(groupby) + !!ensym(subgroupby) +
                    !!ensym(groupby):!!ensym(subgroupby) )

  ## Pass the formula expression to lm()
  model <- lm(frml,data=data)
  print(anova(model))

  ## Compose and evaluate an expression for lsmean() call
  lsm_expr <- expr( lsmeans(model,~!!ensym(groupby):!!ensym(subgroupby)) )
  marginal <- eval(lsm_expr)

  Pletters <- multcomp::cld(marginal, alpha=0.05,
                          Letters=letters, adjust="tukey")
  Pletters$.group=gsub(" ", "", Pletters$.group)
  Pletters
}

## This now produces the desired output
mpg %>% P_letters( y=cty, groupby=drv, subgroupby=class )