簡體   English   中英

返回組最大值和 NA 使用 dplyr

[英]Returning group maximum and NA using dplyr

我需要一個 function 我可以使用它返回組最大值和任何 NA 值。 這是玩具數據:

df <- data.frame(id = rep(1:5, 
                          each = 3),
                 score = rnorm(15))

df$score[c(3,7,10,14)] <- NA

#    id      score
# 1   1 -1.4666164
# 2   1  0.4392647
# 3   1         NA
# 4   2 -0.6010311
# 5   2  1.9845774
# 6   2  0.1749082
# 7   3         NA
# 8   3 -0.3089731
# 9   3  0.4427471
# 10  4         NA
# 11  4  1.7156319
# 12  4 -0.2354253
# 13  5  1.1781350
# 14  5         NA
# 15  5  0.0642082

我可以使用slice_max來獲得每組中的最大值:

df %>%
  group_by(id) %>%
    slice_max(score)

#      id score
#   <int> <dbl>
# 1     1 0.439
# 2     2 1.98 
# 3     3 0.443
# 4     4 1.72 
# 5     5 1.18 

但是我如何獲得最大值加上返回的任何 NA?

我們可以group_by id列,然后使用summarize到 output 具有max的摘要。 在這里,使用了兩個max ,其中一個有na.rm = T ,另一個沒有。 union()用於組合 output ,它同時存在於max中。

library(dplyr)

df %>% 
  group_by(id) %>% 
  summarize(score = union(max(score, na.rm = T), max(score)))  

更新:以上代碼僅在每個 ID 最多有一個NA時才有效。 感謝@KU99 的提醒。

如果每個 ID 有多個NA ,則需要將max的結果與is.na()找到的NA記錄結合起來。

df %>% 
  group_by(id) %>% 
  summarize(score = c(max(score, na.rm = T), score[is.na(score)]))

結果

# A tibble: 9 × 2
# Groups:   id [5]
     id  score
  <int>  <dbl>
1     1  0.735
2     1 NA    
3     2  0.314
4     3  0.994
5     3 NA    
6     4  0.847
7     4 NA    
8     5  1.95 
9     5 NA  

數據

df <- structure(list(id = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 4L, 
4L, 4L, 5L, 5L, 5L), score = c(-1.05089006245306, 0.734652105895187, 
NA, -1.31427279695036, -0.250038722057874, 0.314204596436828, 
NA, 0.994420599790523, 0.855768431757766, NA, 0.834325037545013, 
0.846790152407738, 1.95410525460771, NA, 0.971120269710021)), row.names = c(NA, 
-15L), class = "data.frame")

一種選擇是使用slice| 使用is.na創建邏輯條件以返回NA行和max行。

library(dplyr)

df %>%
  group_by(id) %>% 
  slice(which(score == max(score, na.rm = T)|is.na(score)))

另一種選擇是像您一樣使用slice.max ,然后使用bind_rowsNA值添加回 dataframe。

library(dplyr)

df %>% 
  group_by(id) %>%
  slice_max(score) %>% 
  bind_rows(df %>% filter(is.na(score))) %>% 
  arrange(id)

Output

     id   score
  <int>   <dbl>
1     1 -0.161 
2     1 NA     
3     2  1.49  
4     3 -0.451 
5     3 NA     
6     4  0.878 
7     4 NA     
8     5 -0.0652
9     5 NA     

數據

df <- structure(list(id = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L, 4L, 
4L, 4L, 5L, 5L, 5L), score = c(-0.161217942983375, -0.456571996252207, 
NA, 0.540071362460494, 1.49325799630099, -0.17985218510166, NA, 
-0.451301758592, -0.839100876399644, NA, -0.0432130218441599, 
0.87779273806634, -0.339260854059069, NA, -0.065177224102029)), row.names = c(NA, 
-15L), class = "data.frame")

使用自定義 function 你可以這樣做:

library(dplyr)

set.seed(123)

slice_max_na <- function(.data, order_by, ..., n, prop, with_ties = TRUE) {
  bind_rows(
    slice_max(.data, order_by = {{order_by}}, ..., n = n, prop = prop, with_ties = with_ties),
    filter(.data, is.na({{order_by}})),
  )
}

df %>%
  group_by(id) %>%
  slice_max_na(score)
#> # A tibble: 9 × 2
#> # Groups:   id [5]
#>      id  score
#>   <int>  <dbl>
#> 1     1 -0.230
#> 2     2  1.72 
#> 3     3 -0.687
#> 4     4  1.22 
#> 5     5  0.401
#> 6     1 NA    
#> 7     3 NA    
#> 8     4 NA    
#> 9     5 NA

這是dplyr版本更多使用rank

library(dplyr)

df %>%
  group_by(id) %>%
  mutate(rank = rank(-score, ties.method = "random")) %>% 
  filter(rank == 1 | is.na(score)) %>% 
  select(-rank)
     id  score
  <int>  <dbl>
1     1  0.505
2     1 NA    
3     2 -0.109
4     3 NA    
5     3  1.45 
6     4 NA    
7     4  0.355
8     5 NA    
9     5 -0.298

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM