从列表组合中选择数据框中的行

时间:2017-09-22 00:03:08

标签: r dplyr apply do.call

我有一个数据框,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循环有效,但我认为有一种更有效的方法可以做到这一点,可能使用applydo.call的某些变体。

2 个答案:

答案 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