【问题标题】:filter at with multiple specific conditions在多个特定条件下过滤
【发布时间】:2020-07-07 23:54:51
【问题描述】:

我的数据框遵循以下结构。有一列 A 具有相关的列 A_1、A_2、A_3、A_4,对于 B 也是如此。

# create dummy data frame
dummy_df=data.frame('ID'=c(1,2,3,4),'A'=c('false','false','true','false'),'A_1'=c('false','false','true','false'),'A_2'=c('true','false','false','false'),
                    'A_3'=c('false','false','true','false'),'A_4'=c('false','false','false','false'),'B'=c('false','true','false','false'),'B_1'=c('false','false','false','false'),'B_2'=c('false','true','false','false'),
                    'B_3'=c('false','false','true','false'),'B_4'=c('false','false','false','false') )

我打算做的检查如下:

1) 如果 A 为 = false ,是否有任何行,任何子标题 (A_1,A_2,A_3,A_4 ) 为真,例如下面的 ID 1 (A =false, A_2=true)。为此我在网上研究后得出以下代码

  dummy_df %>% select(matches('ID|A|A_')) %>% filter(A=='false') %>% filter_all(any_vars(. == 'true'))

必须在整个数据框中使用 A 和子列、B 及其子列等进行相同的检查。我无法将上述内容概括为一个函数,我可以只输入我想要检查的基列(即 A 或 B) 并将其应用到基列 (A 或 B) 的列表上,返回 df_A_mistmatch 、 df_B_mismatch(例如行 ID 3) 作为 lapply 函数的输出以及它们在框架中的 ID。

2) 有助于检查上述内容的其他输出是包含所有子列的交叉表,即获取 A=false 和 A_1 或 A_2 或 A_3 或 A_4 = true 的计数>1

在浏览了很多链接后,我发现 filter_at 除了Any_varsall_vars 之外不允许任何其他条件,并且不允许多个条件,例如在这种情况下 - A=false 和 A_1 或 A_2 或 A_3 或A_4 = 真。因此我在下面使用了两个过滤器。

上述问题的最优解是什么

【问题讨论】:

    标签: r filter dplyr


    【解决方案1】:

    这是split.default 的一种方法,适用于任意数量的组 -

    library(dplyr)
    library(purrr)
    
    dummy_df %>%
      select(-1) %>%
      split.default(sub('_.*', '', names(.))) %>%
      imap_dfc(~rowSums(.x[[.y]] == 'false' & .x %>% select(-.y) == 'true'))
    
    #      A     B
    #  <dbl> <dbl>
    #1     1     0
    #2     0     0
    #3     0     1
    #4     0     0
    

    A'false' 时,A 组中的第一行有一个值,其在任何子标题中都有'true',第 3 行中的组B 也是如此。

    【讨论】:

      【解决方案2】:

      我更喜欢使用逻辑值 (TRUE/FALSE) 而不是 'true'/'false' 字符串。

      尝试保留“A = false 且任何子标题 (A_1,A_2,A_3,A_4) = true”的记录

      library(dplyr)
      
      dummy_df %>% 
        mutate_at(vars(-ID), function(x) x == 'true') %>% 
        filter(!A & rowSums(select(., starts_with("A_"))) > 0) %>%
        mutate_at(vars(-ID), function(x) ifelse(x, 'true', 'false'))
      

      PS。第一个mutate 将'true'/'false' 字符串转换为逻辑T/F,最后一个mutate 转换回来。

      输出

      #   ID     A   A_1  A_2   A_3   A_4     B   B_1   B_2   B_3   B_4
      # 1  1 false false true false false false false false false false
      

      【讨论】:

      • 谢谢@Nurandi。我能够实现与上面共享的类似结果,但我渴望获得一个更通用的函数,该函数可以通过应用在所有基列上运行,例如A , B 一次以上。最终结果是一个表,其中包含跨任何基列的所有此类行。类似检查的第二个输出将是跨基础及其所有子列的交叉表
      猜你喜欢
      • 2017-08-29
      • 1970-01-01
      • 2019-01-03
      • 1970-01-01
      • 1970-01-01
      • 2019-08-16
      • 1970-01-01
      • 2014-01-28
      • 1970-01-01
      相关资源
      最近更新 更多