【问题标题】:Data frame dynamic filtering数据框动态过滤
【发布时间】:2017-12-12 16:47:08
【问题描述】:

我想通过一组用户定义的列和值来过滤数据框。

示例数据:test

  col1 col2 col3
1  1    a    4
2  2    b    5
3  3    c    6
4  3    c    7

如果用户指定使用c("col1", "col2") 过滤值c(3, "c"),我希望返回的结果是最后两行。

我尝试了以下方法:

test[test[c("col1", "col2")]==c(3,"c"),]

但是它给出了以下结果:

  col1 col2 col3
3  3    c    6
NA NA   NA   NA

知道为什么最后一行都是 NA 吗? 我该如何解决这个问题?

【问题讨论】:

    标签: r


    【解决方案1】:

    我们需要正确获取行索引。它可以是vectorlogicalnumeric 索引。在比较中(最好使用list 而不是c,因为我们不想混合类)我们得到一个逻辑matrix,需要将其简化为向量。一个选项是rowSums 并检查每行的总和是否等于 2,即用于比较的列数和行子集

    test[rowSums(test[c("col1", "col2")] == list(3, 'c'))==2,]
    #  col1 col2 col3
    #3    3    c    6
    #4    3    c    7
    

    现在,我们看看使用 clist 的方法的区别

    test[c("col1", "col2")]==c(3,"c")
    #  col1  col2
    #1 FALSE FALSE
    #2 FALSE FALSE
    #3  TRUE FALSE
    #4 FALSE  TRUE
    

    在这里,它通过一个接一个地循环元素来比较元素,即对于'col1',将1与3进行比较,然后将2与'c'进行比较,然后再循环向量,即3与3,然后再次下一个3 带“c”。下一列也是如此。

    test[c("col1", "col2")]== list(3,"c")
    #   col1  col2
    #1 FALSE FALSE
    #2 FALSE FALSE
    #3  TRUE  TRUE  #note the change
    #4  TRUE  TRUE
    

    虽然在这里,它将第一列元素与list 的第一个元素进行比较,即list 元素被复制或回收,然后将第二列与第二个list 元素进行比较

    请注意,有 8 个元素,即每列 4 个。因此,碰巧在第一种情况下有 2 个 TRUE 元素,在第二种情况下有 4 个 TRUE 并且有 8 个元素,但是我们只有 4 行,所以当逻辑矩阵的第二列没有行时,它会创建TRUE 值的 NA 行

    test[test[c("col1", "col2")]==c(3,"c"),]
    #   col1 col2 col3
    #3     3    c    6
    #NA   NA <NA>   NA
    

    同样,每列有 2 个 TRUE,再次创建两倍的 NA 行数

    test[test[c("col1", "col2")]==list(3,"c"),]   
    #   col1 col2 col3
    #3       3    c    6
    #4       3    c    7 
    #NA     NA <NA>   NA
    #NA.1   NA <NA>   NA
    

    假设,我们也比较第 3 列,那么会有额外的 NA 行

    test[test==list(3,"c", 5),]
    #     col1 col2 col3
    #3       3    c    6
    #4       3    c    7
    #NA     NA <NA>   NA
    #NA.1   NA <NA>   NA
    #NA.2   NA <NA>   NA
    

    【讨论】:

    • 感谢您的详细解释。
    【解决方案2】:

    这是我的dplyr 解决方案:

    library(dplyr)
    test %>% 
      rowwise() %>% 
      mutate(con = if_else(col1 %in% 3 & col2 %in% "c",TRUE, FALSE)) %>% 
      filter(con == TRUE) %>% 
      select(-con)  %>% 
      ungroup
    

    【讨论】:

      【解决方案3】:

      另一个带有 tidyeval 的 dplyrversion

      library(dplyr)
      column_equals <- function(df, ...) {
        conditions <- quos(...)
        df %>%  
          filter(!!!conditions)
      }
      
      test %>%  
        column_equals(col1 == 3 & col2 == "c")
      

      【讨论】:

        【解决方案4】:

        这是为了将akrun answer 扩展到更真实的示例,其中搜索列中的数据可能包含NA。在这种情况下,最终输出中会出现“NA”行,这很混乱,可能会混淆下游分析。在此示例中,我使用 NA 值对列 numcol2 进行了加标。只有col2 中的NA 有效,因为它用于搜索。这个问题的根源是任何与NA 一起操作的东西都会给出NA(例如NA == 1 = NA),除了is.na

        mydf <- data.frame(num = c(1:3, NA, 5, 6), col1 = c('a', 'b', 'a', 'b', 'c', 'd'), col2 = c('A', 'b', 'A', 'B', NA, 'D'), col3 = as.character(letters)[1:6])
        getrows = mydf[c("col2", "col1")] == list("A", "a") # Mixing up column orders for fun
        getrows = rowSums(getrows) == 2
        getrows
        mydf[getrows, ] # This gives undesired NA rows
        # Use which to get exact row number
        which(getrows)
        mydf[which(getrows),] 
        

        比较下面的输出:

        > mydf <- data.frame(num = c(1:3, NA, 5, 6), col1 = c('a', 'b', 'a', 'b', 'c', 'd'), col2 = c('A', 'b', 'A', 'B', NA, 'D'), col3 = as.character(letters)[1:6])
        > getrows = mydf[c("col2", "col1")] == list("A", "a") # Mixing up column orders for fun
        > getrows = rowSums(getrows) == 2
        > getrows
        [1]  TRUE FALSE  TRUE FALSE    NA FALSE
        > mydf[getrows, ] # This gives undesired NA rows
           num col1 col2 col3
        1    1    a    A    a
        3    3    a    A    c
        NA  NA <NA> <NA> <NA>
        > # Use which to get exact row number
        > which(getrows)
        [1] 1 3
        > mydf[which(getrows),]
          num col1 col2 col3
        1   1    a    A    a
        3   3    a    A    c
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-02-06
          • 2019-06-12
          • 1970-01-01
          • 2015-04-29
          • 1970-01-01
          • 2020-10-08
          • 1970-01-01
          相关资源
          最近更新 更多