子集仅返回多行分组的完整案例

时间:2018-11-14 12:43:03

标签: r dplyr data.table plyr tidyr

如果我有一个data.frame,DF,具有5个变量,这些变量具有1到24行之间的不同组-以此为例:

GROUP_ID    VAR_1    VAR_2    VAR_3    VAR_4    VAR_5
1             2        4        5        6        6
1             3        4        2        3        4
1             4       NA        6        6        3
1             3        2        1        2        4
2             9        8        2        7        1
2             2        3        3        2        6
2             2        5        8        9        2
3             2        1        5        6       NA
3            NA       NA        5        8        9
3             4        2        6        8        7

在这种情况下,完整的情况将被定义为在具有相应group_ID的任何行中的任何变量中都没有NA的组。在此示例中,只有GROUP_ID 2代表完整的情况。

如何以这种方式对data.frame进行子集化,使其找到具有完整案例的组并返回具有该组ID的所有行(在本示例中,仅返回GROUP_ID 2的所有行)?

4 个答案:

答案 0 :(得分:1)

这是一个简单的单行基础R解决方案-

DF[ave(complete.cases(DF), DF$GROUP_ID, FUN = all), ]

  GROUP_ID VAR_1 VAR_2 VAR_3 VAR_4 VAR_5
5        2     9     8     2     7     1
6        2     2     3     3     2     6
7        2     2     5     8     9     2

答案 1 :(得分:0)

使用ave的基本R方法将

df[as.logical(ave(rowSums(is.na(df)), df$GROUP_ID, 
                     FUN = function(x) all(x == 0))), ]

#  GROUP_ID VAR_1 VAR_2 VAR_3 VAR_4 VAR_5
#5        2     9     8     2     7     1
#6        2     2     3     3     2     6
#7        2     2     5     8     9     2

我们计算每行NA的数量,并为每个NA中的行值all过滤具有0 GROUP_ID的行。 / p>


或更简洁的结果相同

df[ave(rowSums(is.na(df)) == 0, df$GROUP_ID, FUN = all), ]

答案 2 :(得分:0)

您可以为此使用dplyr。首先group_by您的分组变量,然后使用filter_at筛选您关心的完整案例的变量。在这里,我们使用starts_with选择所有VAR变量(实际上因为没有其他列可以使用filter_all)。然后,我们使用all_vars来包装谓词,该谓词检查值是否不丢失。基本上是说:“对于每个组,检查all每一列中的值是否不丢失。如果所有列(all_vars都为真,则保留该行。”

library(tidyverse)
tbl <- structure(list(GROUP_ID = c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), VAR_1 = c(2L, 3L, 4L, 3L, 9L, 2L, 2L, 2L, NA, 4L), VAR_2 = c(4L, 4L, NA, 2L, 8L, 3L, 5L, 1L, NA, 2L), VAR_3 = c(5L, 2L, 6L, 1L, 2L, 3L, 8L, 5L, 5L, 6L), VAR_4 = c(6L, 3L, 6L, 2L, 7L, 2L, 9L, 6L, 8L, 8L), VAR_5 = c(6L, 4L, 3L, 4L, 1L, 6L, 2L, NA, 9L, 7L)), row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"), spec = structure(list(cols = list(GROUP_ID = structure(list(), class = c("collector_integer", "collector")), VAR_1 = structure(list(), class = c("collector_integer", "collector")), VAR_2 = structure(list(), class = c("collector_integer", "collector")), VAR_3 = structure(list(), class = c("collector_integer", "collector")), VAR_4 = structure(list(), class = c("collector_integer", "collector")), VAR_5 = structure(list(), class = c("collector_integer", "collector"))), default = structure(list(), class = c("collector_guess", "collector"))), class = "col_spec"))

tbl %>%
  group_by(GROUP_ID) %>%
  filter_at(vars(starts_with("VAR")), all_vars(all(!is.na(.))))
#> # A tibble: 3 x 6
#> # Groups:   GROUP_ID [1]
#>   GROUP_ID VAR_1 VAR_2 VAR_3 VAR_4 VAR_5
#>      <int> <int> <int> <int> <int> <int>
#> 1        2     9     8     2     7     1
#> 2        2     2     3     3     2     6
#> 3        2     2     5     8     9     2

reprex package(v0.2.1)于2018-11-14创建

答案 3 :(得分:0)

这是另一种使用每组NA的数量的情况(如果您对此也很感兴趣)。

GROUP_ID.NA.COUNT <- tapply(rowSums(is.na(DF[paste("VAR", 1:5, sep = "_")])),
                            DF$GROUP_ID, FUN = sum) # number of NA per group based on values from VAR_1 to VAR_5
DF[DF$GROUP_ID %in% which(GROUP_ID.NA.COUNT == 0), ] # Subset to only return group with 0 NA based on values from VAR_1 to VAR_5

# output
  GROUP_ID VAR_1 VAR_2 VAR_3 VAR_4 VAR_5
5        2     9     8     2     7     1
6        2     2     3     3     2     6
7        2     2     5     8     9     2