【问题标题】:Designing a function so filter does not drop NAs设计一个函数,使过滤器不会丢弃 NA
【发布时间】:2019-07-06 19:01:40
【问题描述】:

我最近才被 dplyr::filter 在过滤时从我的 tibble 中删除大量 NA 咬伤。我大部分时间都在研究完整的数据集,但现在我正在冒险研究更混乱的数据,我想在其中进行比较。因此,我想创建一个与过滤器具有相同功能但不删除 NA 的函数。以下是一些建议:Why does dplyr's filter drop NA values from a factor variable?How to filter data without losing NA rows using dplyr 但是在处理大量缺失数据值和许多比较时,它们是繁琐的解决方案。下面是一些绕过它的方法的示例。

这是样本数据,A 列和 B 列都缺少 NA

df = tibble(A = rep(c(1,2,3,NA,NA),10000),
            B = rep(c(NA,1,2,3,4),10000))

这就是我想要做的直觉。返回 A 不等于 B 的值,但它会丢弃所有 NA(如预期的那样)。

df %>% filter(A != B)

第一个解决方案:解决此问题的解决方案是使用基础 R 中的 %in%,但您需要逐行执行此操作,然后取消分组,因此会减慢处理速度。但是当它们出现在 A 或 B 中时,通过保留 NA 来给出正确的结果。

df %>% rowwise() %>%  filter(!A %in% B) %>% ungroup()

第二个解决方案:之前建议的另一个选项是使用 |如果 A 和 B 为 NA,则返回它们。

df %>% filter(A != B|is.na(A)|is.na(B))

现在,如果您要进行多次过滤和比较,这会变得很烦人,而且您可能会在某个地方塞满东西!因此,是否可以创建一个自动使 is.na() 保持内置的函数。也许是这样的。

    filter_keepna = function(data, expression){
data %>% filter(expression|is.na(column1)|is.na(column2)
}

我没有足够的知识来完成这样的事情。但我从各种平台上的所有 cmets 中假设这是必需的。

【问题讨论】:

标签: r filter dplyr na


【解决方案1】:

在您的函数中,您可以使用 rlang 包中的函数进行整洁的评估。 enquo()f_lhs()quo_get_expr() 函数可以帮助从表达式中提取变量。您还需要 bang bang 运算符 (!!) 来解释 quosures。在你的例子中,是:

filter_keepna <- function(data, expre){
  expre <- enquo(expre) #Quotation 

  data %>% 
    filter(!!expre | #!! is a tidy evaluator

             # get quoted left variable from expre
             is.na(!!f_lhs(quo_get_expr(expre))) |

             # get quoted right variable from expre
             is.na(!!f_rhs(quo_get_expr(expre))))
}

在示例数据中使用 filter_keepna() 函数:

df = tibble(A = rep(c(1,2,3,NA,NA),10000),
            B = rep(c(NA,1,2,3,4),10000))

filter_keepna(df, A != B)
# A tibble: 40,000 x 2
#        A     B
#     <dbl> <dbl>
#  1     2     1
#  2     3     2
#  3    NA     3
#  4    NA     4
#  5     2     1
#  6     3     2
#  7    NA     3
#  8    NA     4
#  9     2     1
# 10     3     2
# # ... with 39,990 more rows

详细信息在 rlang 包的quotation referenceQuosure getters reference 中。 .........

【讨论】:

    【解决方案2】:

    试试coalesce

    df %>% filter(coalesce(A != B, TRUE))
    

    【讨论】:

    • 不适合过滤,因为TRUE包含了条件A != B的补足。您可以使用all_equal(df %&gt;% filter(coalesce(A != B, TRUE)), df) 进行测试
    • 这似乎是 OP 想要的。 all_equal(df %&gt;% filter(coalesce(A != B, TRUE)), df) 并不总是正确的;对于这种特殊情况,它恰好是真的。
    • 我喜欢使用 coalesce 的灵活性,这意味着我可以在一个 filter() 调用中组合多个过滤选项,从而增加了灵活性。 @gavg712 正是我最初问题的解决方案,这种合并更方便。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多