我想创建一个基于列内少量依赖关系的数据清理规则。例如,如果Q3是3,那么我需要检查Q1是否为空。我可以用这样一个简单的命令来做:
df$Q1chk<-ifelse(df$Q3==3 & is.na(df$Q1), 1,0)
,其中final Q1chk中的1表示ok。现在,由于我有很多条件和列,我希望有更灵活和优雅的解决方案。首先我要分配一个过滤器检查像这样的列:attr(df$Q1, "filter")<-"Q3==3"
,然后对整个数据集运行一个函数。condition可能与"=="运营商。
如何传递字符串条件"Q3==3"到函数,让它工作。我试过这样做:
ChkF<-function(dat, var) {
exp<- attr(dat[[var]], "filter")
dat[[paste0("chk",var)]]<- ifelse(is.na(dat[[var]]) & dat[eval(rlang::parse_expr(exp))==TRUE], 1 , 0)
}
但它不起作用。我知道这个表达式:dat[["Q3"]]==3
工作得很好,但简单地用方括号替换引号(从"Q3==3"[["Q3"]]==3)看起来不像一个优雅的解决方案。有没有更合适的方法?最后,我想在一列中结合使用许多条件,例如:attr(df$Q1, "filter")<-c("Q3==3", "Q4>1", "Q5 %in% 2:7")
,所以这就是为什么我想保持条件的语法尽可能简单的原因。
使用data.table
:
library(data.table)
set.seed(1)
##
# made up example
#
dt <- data.table(Q3=rpois(100, 3), Q4=rnorm(100, 1), Q5=rnbinom(100, mu=7, size=50))
##
# you start here
#
filters <- lapply(c("Q3==3", "Q4>1", "Q5 %in% 2:7"), str2expression)
dt[, lapply(filters, (x) as.integer(eval(x))), by=.(Q3, Q4, Q5)]
## Q3 Q4 Q5 V1 V2 V3
## 1: 2 1.39810588 7 0 1 1
## 2: 2 0.38797361 4 0 0 1
## 3: 3 1.34111969 7 1 1 1
## 4: 5 -0.12936310 7 0 0 1
## 5: 2 2.43302370 5 0 1 1
## 6: 5 2.98039990 10 0 1 0
## ...