基于很多条件的多列汇总

时间:2018-12-04 13:19:50

标签: r dplyr

样本数据

df <- data.frame( id = 1:10,
                  group = c(1,1,1,1,1,2,2,2,2,2),
                  p1 = c("A", NA, "A", "A", "B", NA, NA, NA, NA, "C"),
                  p2 = c("F", NA, "G", "G", "A", "H", NA, NA, NA, NA),
                  stringsAsFactors = FALSE )

#     id group   p1   p2
#  1   1     1    A    F
#  2   2     1 <NA> <NA>
#  3   3     1    A    G
#  4   4     1    A    G
#  5   5     1    B    A
#  6   6     2 <NA>    H
#  7   7     2 <NA> <NA>
#  8   8     2 <NA> <NA>
#  9   9     2 <NA> <NA>
# 10  10     2    C <NA>

我想按组总结df,以便获得总计的列

  • 唯一ID
  • 任何p列值都不为NA的唯一ID
  • 任何p列值均等于“ A”的唯一ID

所需的输出

data.frame( group = c(1,2),
            total = c(5,5),
            with_any_p = c(4,2),
            with_any_p_is_A = c(4,0),
            stringsAsFactors = FALSE)

#   group total with_any_p with_any_p_is_A
# 1     1     5          4               4
# 2     2     5          2               0
到目前为止的

代码

我知道我可以使用以下方法获得所需的输出

df %>% group_by( group ) %>% 
  summarise( total = n_distinct( id[] ),
             with_any_p = n_distinct( id[ !is.na(p1) | ! is.na(p2) ] ), 
             with_any_p_is_A = n_distinct( id[ p1 == "A" | p2 == "A" ], na.rm = TRUE ) )

# # A tibble: 2 x 4
#   group total with_any_p with_any_p_is_A
#   <dbl> <int>      <int>           <int>
# 1     1     5          4               4
# 2     2     5          2               0

问题

但是由于我的生产数据包含很多“ p列”,所以我不想为p1-p100重新输入上述or语句

我可以使用filter_at选择所需的行/子集:

p.cols <- paste0( "p", 1:2 )
#for with_any_p
df %>% filter_at( vars( p.cols ), any_vars( !is.na(.) ) )
#for with_any_p_is_A
df %>% filter_at( vars( p.cols ), any_vars( . == "A" ) )

但我现在确实知道如何总结这些选择。

能否以与我已有的代码相同的“样式”完成操作,以便一劳永逸地获得所需结果,而不必绑定/合并多个结果?

1 个答案:

答案 0 :(得分:3)

这是使用初始的宽到长转换为任意数量的"p"列的解决方案

df %>%
    gather(key, val, -id, -group) %>%
    group_by(group) %>%
    summarise(
        total = n_distinct(id),
        with_any_p = n_distinct(id[!is.na(val)]),
        with_any_p_is_A = n_distinct(id[val == "A"], na.rm = T))
## A tibble: 2 x 4
#  group total with_any_p with_any_p_is_A
#  <dbl> <int>      <int>           <int>
#1     1     5          4               4
#2     2     5          2               0

评论:我假设除idgroup以外的所有列均为"p"列。如果不是这种情况,则可能必须更改gather语句以反映您更一般的列结构。