我有一个数据框,dat:
dat<-data.frame(col1=rep(1:4,3),
col2=rep(letters[24:26],4),
col3=letters[1:12])
我想仅使用数据框dat
中的行给出的组合,在两个不同的列上过滤filter
:
filter<-data.frame(col1=1:3,col2=NA)
lists<-list(list("x","y"),list("y","z"),list("x","z"))
filter$col2<-lists
因此,例如,将选择包含(1,x)和(1,y)的行,但不选择(1,z),(2,x)或(3,y)。
我知道如何使用for循环来实现它:
#create a frame to drop results in
results<-dat[1,]
for(f in 1:nrow(filter)){
temp_filter<-filter[f,]
temp_dat<-dat[dat$col1==temp_filter[1,1] &
dat$col2%in%unlist(temp_filter[1,2]),]
results<-rbind(results,temp_dat)
}
或者如果您更喜欢dplyr风格:
require(dplyr)
results<-dat[0,]
for(f in 1:nrow(filter)){
temp_filter<-filter[f,]
temp_dat<-filter(dat,col1==temp_filter[1,1] &
col2%in%unlist(temp_filter[1,2])
results<-rbind(results,temp_dat)
}
结果应该返回
col1 col2 col3
1 1 x a
5 1 y e
2 2 y b
6 2 z f
3 3 z c
7 3 x g
我通常会使用合并进行过滤,但我现在不能,因为我必须针对列表而不是单个值检查col2。 for循环有效,但我认为有一种更有效的方法可以做到这一点,可能使用apply
或do.call
的某些变体。
答案 0 :(得分:1)
如果我们有两个数据帧,我们可以使用if (condition) {
// this stuff happens if condition is true...
} else {
// ...otherwise this other stuff happens
}
为我们执行行排除过滤:
dplyr::anti_join()
答案 1 :(得分:1)
主要基于dplyr
的一点帮助:
dplyr::setdiff(dat,merge(dat,setNames(as.data.frame(filter),names(dat)[1:2])))
col1 col2 col3
1 4 x d
2 1 y e
3 2 z f
4 3 x g
5 4 y h
6 1 z i
7 2 x j
8 3 y k
9 4 z l
一个真正的基础R解决方案虽然不那么漂亮但你丢失了行顺序:
subset(merge(dat,`[[<-`(setNames(as.data.frame(filter),names(dat)[1:2]),"x",value=1),all.x=T),is.na(x),-4)
col1 col2 col3
2 1 y e
3 1 z i
4 2 x j
6 2 z f
7 3 x g
8 3 y k
10 4 x d
11 4 y h
12 4 z l