在dplyr中使用group_by删除具有多个NAs的行

时间:2018-05-02 16:19:52

标签: r dplyr

我有这个玩具数据框架:

df <- data.frame(id=c(1,1,2,3,4,4),p_id=c(1001,1001,1002,1003,1004,1004),x=c(1,NA,1,2,NA,1),y=c(NA,5,4,NA,6,NA),z=c(NA,NA,2,3,NA,4))

id p_id  x  y   z
1  1001  1  NA  NA
1  1001 NA  5   NA
2  1002  1  4    2
3  1003  2  NA   3
4  1004 NA  6   NA
4  1004  1  NA   4

我想获得具有唯一“p_id”行的最终输出,并且从x,y和z(理想情况下,应该可以在任意数量的列上工作)中删除不需要的NA值。示例输出:

p_id    x    y     z
1001    1    5     NaN
1002    1    4     2
1003    2  NaN     3
1004    1    6     4

我正在做这个快速解决方法(不确定最佳方法):

df %>% select(-id) %>% group_by(p_id) %>% summarise_all(funs(mean),na.rm=T) %>% ungroup()

但是,当应用于大型数据帧(2500 x 650)时,此解决方法非常慢,并且会为正常单元格创建不需要的NA。同样对于上下文,此df中具有NA的重复p_id行来自扩展函数。

2 个答案:

答案 0 :(得分:1)

按“ID”列进行分组后,如果每个组中该列中的所有元素均为summarise_all,则通过创建if/else条件返回NaN来执行NA或者取非NA元素(在这个例子中,只有一个非NA元素,所以我们将它子集化)

df %>%
  group_by(id, p_id) %>%
  summarise_all(funs(if(all(is.na(.))) NaN else .[!is.na(.)]))
# A tibble: 4 x 5
# Groups:   id [?]
#     id  p_id     x     y     z
#  <dbl> <dbl> <dbl> <dbl> <dbl>
#1     1  1001     1     5   NaN
#2     2  1002     1     4     2
#3     3  1003     2   NaN     3
#4     4  1004     1     6     4

如果每个组ID组合的NA值超过非NA值,那么我们可以使用mean(如OP的帖子所示)

df %>% 
  group_by(id, p_id) %>% 
  summarise_all(funs(if(all(is.na(.))) NaN else mean(., na.rm = TRUE)))

答案 1 :(得分:0)

您可以使用tidyr::fill()后跟summarize

 df %>% 
   group_by(id) %>%  
   fill(x,y,z, .direction = "up") %>% 
   summarise_all(first)
#> # A tibble: 4 x 5
#>      id  p_id     x     y     z
#>   <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1     1  1001     1     5    NA
#> 2     2  1002     1     4     2
#> 3     3  1003     2    NA     3
#> 4     4  1004     1     6     4