如何对组应用一系列自定义操作
How to apply a sequence of custom operations on a group by
我有以下形式的数据框:
ID
Rank
Var1
Var2
a
3
na
6
b
2
3
na
a
1
na
5
a
2
2
1
b
1
7
1
我正在尝试应用一系列操作:
- 按 ID 列分组
- 按排名列降序排列
- 对于每个变量列,select 排名最高的非 na 值
所以输出将是
ID
Var1
Var 2
a
2
6
b
3
1
到目前为止我有
df %>% group_by(ID) %>% arange(desc(Rank))
但我不确定如何过滤每列的非 NA 和 select 最高值。 NA 过滤器应仅应用于列 - 如果 Var 1 具有 na,则应将其排除在 Var 1 的计算之外,但不适用于 Var2。
Select 分组后所选变量的第一个 non-NA 值:
library(dplyr)
df %>%
na_if("na") %>%
group_by(ID) %>%
arrange(desc(Rank), .by_group = T) %>%
summarise(across(Var1:Var2, ~ head(.x[!is.na(.x)], 1)))
# A tibble: 2 × 3
ID Var1 Var2
<chr> <chr> <chr>
1 a 2 6
2 b 3 1
或 first
:
df %>%
na_if("na") %>%
group_by(ID) %>%
summarise(across(Var1:Var2, ~ first(.x[!is.na(.x)], order_by = "Rank")))
数据
df <- read.table(header = T, text = "ID Rank Var1 Var2
a 3 na 6
b 2 3 na
a 1 na 5
a 2 2 1
b 1 7 1")
library(tidyverse)
tribble(
~ID, ~Rank, ~Var1, ~Var2,
"a", 3, NA, 6,
"b", 2, 3, NA,
"a", 1, NA, 5,
"a", 2, 2, 1,
"b", 1, 7, 1
) |>
group_by(ID) |>
arrange(ID, desc(Rank)) |>
fill(everything(), .direction = "up") |>
summarise(across(starts_with("Var"), first))
#> # A tibble: 2 × 3
#> ID Var1 Var2
#> <chr> <dbl> <dbl>
#> 1 a 2 6
#> 2 b 3 1
由 reprex package (v2.0.1)
于 2022-05-11 创建
另一个可能的解决方案:
library(tidyverse)
map(c("Var1", "Var2"), ~
select(df, ID, Rank, all_of(.x)) %>%
group_by(ID) %>%
drop_na() %>%
slice_max(Rank) %>%
ungroup %>% select(-Rank)) %>%
reduce(inner_join)
#> Joining, by = "ID"
#> # A tibble: 2 x 3
#> ID Var1 Var2
#> <chr> <int> <int>
#> 1 a 2 6
#> 2 b 3 1
我有以下形式的数据框:
ID | Rank | Var1 | Var2 |
---|---|---|---|
a | 3 | na | 6 |
b | 2 | 3 | na |
a | 1 | na | 5 |
a | 2 | 2 | 1 |
b | 1 | 7 | 1 |
我正在尝试应用一系列操作:
- 按 ID 列分组
- 按排名列降序排列
- 对于每个变量列,select 排名最高的非 na 值 所以输出将是
ID | Var1 | Var 2 |
---|---|---|
a | 2 | 6 |
b | 3 | 1 |
到目前为止我有
df %>% group_by(ID) %>% arange(desc(Rank))
但我不确定如何过滤每列的非 NA 和 select 最高值。 NA 过滤器应仅应用于列 - 如果 Var 1 具有 na,则应将其排除在 Var 1 的计算之外,但不适用于 Var2。
Select 分组后所选变量的第一个 non-NA 值:
library(dplyr)
df %>%
na_if("na") %>%
group_by(ID) %>%
arrange(desc(Rank), .by_group = T) %>%
summarise(across(Var1:Var2, ~ head(.x[!is.na(.x)], 1)))
# A tibble: 2 × 3
ID Var1 Var2
<chr> <chr> <chr>
1 a 2 6
2 b 3 1
或 first
:
df %>%
na_if("na") %>%
group_by(ID) %>%
summarise(across(Var1:Var2, ~ first(.x[!is.na(.x)], order_by = "Rank")))
数据
df <- read.table(header = T, text = "ID Rank Var1 Var2
a 3 na 6
b 2 3 na
a 1 na 5
a 2 2 1
b 1 7 1")
library(tidyverse)
tribble(
~ID, ~Rank, ~Var1, ~Var2,
"a", 3, NA, 6,
"b", 2, 3, NA,
"a", 1, NA, 5,
"a", 2, 2, 1,
"b", 1, 7, 1
) |>
group_by(ID) |>
arrange(ID, desc(Rank)) |>
fill(everything(), .direction = "up") |>
summarise(across(starts_with("Var"), first))
#> # A tibble: 2 × 3
#> ID Var1 Var2
#> <chr> <dbl> <dbl>
#> 1 a 2 6
#> 2 b 3 1
由 reprex package (v2.0.1)
于 2022-05-11 创建另一个可能的解决方案:
library(tidyverse)
map(c("Var1", "Var2"), ~
select(df, ID, Rank, all_of(.x)) %>%
group_by(ID) %>%
drop_na() %>%
slice_max(Rank) %>%
ungroup %>% select(-Rank)) %>%
reduce(inner_join)
#> Joining, by = "ID"
#> # A tibble: 2 x 3
#> ID Var1 Var2
#> <chr> <int> <int>
#> 1 a 2 6
#> 2 b 3 1