【发布时间】:2019-11-08 22:35:34
【问题描述】:
我正在尝试编写一个函数,该函数采用两个列名以及每个列名的上限和/或下限,这样我就可以使用我选择的列名和边界对数据进行子集化。
以 mtcars 为例,如果我想通过说我只想要具有 cyl > 4 和 mpg > 15 的行来对数据进行子集化,在这种情况下,我的函数将采用两个列名 cyl 和 mpg ,每个列名也有两个下边界,分别是 4 和 15。当然,在函数中,我可以选择为其分配一个上边界,以将列名(变量)保持在一定范围内。
所以我想出了类似下面的东西,一个函数,它接受您选择的两个变量名称以及每个变量的上限和/或下限。
如果我只给这个变量一个上限或下限,那么它会给我小于或大于这个边界的任何东西,如果我给函数同时给出上限和下限,它会给我返回范围内的行.
comb_function<-function(df,var1,var2,var1_lower=NULL,var1_upper=NULL,var2_upper=NULL,var2_lower=NULL){
var1<-enexpr(var1)
var2<-enexpr(var2)
#####for var2,if upper boundary are given by user,do this#####{
filter1<-expr(`$`(df,!!var2))<=var2_upper
#for var1, if upper boundary are given by user,do this# {
filter2<-expr(`$`(df,!!var1))<=var1_upper}
#for var 1,if lower boundary are given by user, do this#{
filter2<-expr(`$`(df,!!var1))>=var1_lower}
#for var1, if both are given by user, do this#{
filter2<-expr(`$`(df,!!var1))>=var1_lower&expr(`$`(df,!!var1))<=var1_upper}
}
#####for var2,if lower boundary are given by user,do this#####{
filter1<-expr(`$`(df,!!var2))>=var2_lower
#for var1,if upper boundary are given by user,do this#{
filter2<-expr(`$`(df,!!var1))<=var1_upper}
#for var1,if lower boundary are given by user,do this#{
filter2<-expr(`$`(df,!!var1))>=var1_lower}
#if both are given by the user,do this{
filter2<-expr(`$`(df,!!var1))>=var1_lower&expr(`$`(df,!!var1))<=var1_upper}
}
#####for var2,if both are given by user,do this#####{
filter1<-expr(`$`(df,!!var2))<=var2_upper&expr(`$`(df,!!var2))>=var2_lower
#for var1,if upper boundary are given by user,do this#{
filter2<-expr(`$`(df,!!var1))<=var1_upper}
#for var1,if lower boundary are given by user,do this#{
filter2<-expr(`$`(df,!!var1))>=var1_lower}
#if both are given by user, do this#{
filter2<-expr(`$`(df,!!var1))>=var1_lower&expr(`$`(df,!!var1))<=var1_upper}
}
output<-df%>%filter(filter1,filter2)%>%summarise(count=n(),avgcyl=mean(cyl,na.rm=TRUE))
return(output)
}
当我以 mtcars 为例调用这个函数时
final1<-comb_function(df=mtcars,var1=mpg,var2=cyl,var1_lower =15,var2_lower=4,var2_upper=6)
我在 final1 中得到 0 个计数和 avgcrl 的 NaN。因此,当filter() 评估() 中的内容时,它只会得到 FALSE,而不是 TRUE,我认为这就是没有返回行的原因。
我对为什么会发生这种情况有一个理论。如果我这样做:
x<-expr(cyl);eval(expr(expr(`$`(mtcars,!!x))<=6))
返回:
[1]FALSE
这显然不是我所期望的。如果我这样做:
eval(expr(`$`(mtcars,!!x)))<=6
返回
[1] TRUE TRUE TRUE TRUE FALSE TRUE FALSE TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE FALSE
[23] FALSE FALSE FALSE TRUE TRUE TRUE FALSE TRUE FALSE TRUE
这就是我想要的 filter() 函数中的函数。所以我猜当filter() 评估() 里面的内容时,它会自动将括号括在整个表达式中,就像
eval(expr(expr(`$`(mtcars,!!x))<=6))
did,它只返回一个 FALSE。因此,如果这真的是我所期望的原因,我该如何让filter() 知道我真正想要的是让它像这样评估:
eval(filter1<-expr(`$`(df,!!var2)))<=var2_upper
不是这个:
eval(filter1<-expr(`$`(df,!!var2))<=var2_upper)
如果我猜的不是怎么回事,也请帮助我。
【问题讨论】:
-
我建议尽可能简化您的问题。尤其是第一个 sn-p 代码非常复杂且难以阅读。
标签: r dplyr lazy-evaluation tidyeval non-standard-evaluation