【问题标题】:Selecting rows from a data frame from combinations of lists [duplicate]从列表组合中选择数据框中的行[重复]
【发布时间】:2017-09-22 00:03:08
【问题描述】:

我有一个数据框,dat:

dat<-data.frame(col1=rep(1:4,3),
                col2=rep(letters[24:26],4),
                col3=letters[1:12])

我想仅使用数据框filter 中的行给出的组合在两个不同的列上过滤dat

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 的一些变体。

【问题讨论】:

    标签: r dplyr apply do.call


    【解决方案1】:

    如果我们有两个数据框,我们可以使用dplyr::anti_join() 为我们进行行排除过滤:

    index <- data.frame(col1 = as.character(filter[,1]),
                        col2 = filter[,2])
    
    anti_join(dat, index)
    
    Joining, by = c("col1", "col2")
      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
    

    【讨论】:

      【解决方案2】:

      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
      

      【讨论】:

      • 哎呀,好的,我会修改它,谢谢
      • 该死的,好收获
      • Base R 并没有很好地完成这个特定的合并。我能想到的最好办法是根据重复的链接问题使用interaction()
      • 哦,是的,互动绝对比我带来的奇怪东西更干净:)。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-28
      • 2021-02-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多