如何使用 dplyr 的 coalesce 函数和 group_by() 为每个人创建一行并填充所有值?
How to use dplyr's coalesce function with group_by() to create one row per person with all values filled in?
我正在尝试使用 coalesce() 为每个参与者生成一行,其中包含他们的姓名和分数。参与者有 3 次填写数据的机会,大多数只填写一次(多次填写的总是相同的数据)。所以我的数据看起来像:
library(dplyr)
test_dataset <- tibble(name = c("justin", "justin", "justin", "corey", "corey", "corey", "sib", "sib", "sib", "kate", "kate", "kate"),
score1 = c(NA_real_, NA_real_, 1, 2, NA_real_, NA_real_, 2, NA_real_, 2, NA_real_, NA_real_ , NA_real_),
score2 = c(NA_real_, 7, NA_real_, 5, NA_real_, NA_real_, 9, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_))
我希望它看起来像:
library(dplyr)
answer <- tibble(name = c("justin", "corey", "sib", "kate"),
score1_true = c(1, 2, 2, NA),
score2_true = c(7, 5, 9, NA))
我已经尝试了以下解决方案,它确实给了我 'true' 分数,但它分布在 12 行(每人 3 行)而不是 4 行(每人一个):
library(dplyr)
test_dataset %>%
dplyr::group_by(name) %>%
mutate(across(c(starts_with("score")), .fns = list(true = ~coalesce(.))))
我们可以根据 NA
元素对值重新排序,然后对第一行进行切片
library(dplyr)
test_dataset %>%
group_by(name) %>%
dplyr::mutate(across(starts_with('score'),
~ .x[order(is.na(.x))])) %>%
slice_head(n = 1) %>%
ungroup
-输出
# A tibble: 4 × 3
name score1 score2
<chr> <dbl> <dbl>
1 corey 2 5
2 justin 1 7
3 kate NA NA
4 sib 2 9
或者另一种选择是在重新排列后使用 complete.cases
test_dataset %>%
group_by(name) %>%
dplyr::mutate(across(starts_with('score'),
~ .x[order(is.na(.x))])) %>%
filter(complete.cases(across(starts_with('score')))|row_number() == 1) %>%
ungroup
-输出
# A tibble: 4 × 3
name score1 score2
<chr> <dbl> <dbl>
1 justin 1 7
2 corey 2 5
3 sib 2 9
4 kate NA NA
您可以使用 fill()
,然后 arrange()
分数并使用 slice_head()
:
test_dataset %>%
group_by(name) %>%
fill(score1, score2) %>%
arrange(score1, score2) %>%
slice_head(n=1)
输出:
name score1_true score2_true
<chr> <dbl> <dbl>
1 justin 1 7
2 corey 2 5
3 sib 2 9
4 kate NA NA
更多concise/improved版本感谢@M.Viking:
- 在
fill()
中使用 .direction="up"
选项
test_dataset %>%
group_by(name) %>%
fill(score1, score2, .direction="up") %>%
slice_head(n=1)
我正在尝试使用 coalesce() 为每个参与者生成一行,其中包含他们的姓名和分数。参与者有 3 次填写数据的机会,大多数只填写一次(多次填写的总是相同的数据)。所以我的数据看起来像:
library(dplyr)
test_dataset <- tibble(name = c("justin", "justin", "justin", "corey", "corey", "corey", "sib", "sib", "sib", "kate", "kate", "kate"),
score1 = c(NA_real_, NA_real_, 1, 2, NA_real_, NA_real_, 2, NA_real_, 2, NA_real_, NA_real_ , NA_real_),
score2 = c(NA_real_, 7, NA_real_, 5, NA_real_, NA_real_, 9, NA_real_, NA_real_, NA_real_, NA_real_, NA_real_))
我希望它看起来像:
library(dplyr)
answer <- tibble(name = c("justin", "corey", "sib", "kate"),
score1_true = c(1, 2, 2, NA),
score2_true = c(7, 5, 9, NA))
我已经尝试了以下解决方案,它确实给了我 'true' 分数,但它分布在 12 行(每人 3 行)而不是 4 行(每人一个):
library(dplyr)
test_dataset %>%
dplyr::group_by(name) %>%
mutate(across(c(starts_with("score")), .fns = list(true = ~coalesce(.))))
我们可以根据 NA
元素对值重新排序,然后对第一行进行切片
library(dplyr)
test_dataset %>%
group_by(name) %>%
dplyr::mutate(across(starts_with('score'),
~ .x[order(is.na(.x))])) %>%
slice_head(n = 1) %>%
ungroup
-输出
# A tibble: 4 × 3
name score1 score2
<chr> <dbl> <dbl>
1 corey 2 5
2 justin 1 7
3 kate NA NA
4 sib 2 9
或者另一种选择是在重新排列后使用 complete.cases
test_dataset %>%
group_by(name) %>%
dplyr::mutate(across(starts_with('score'),
~ .x[order(is.na(.x))])) %>%
filter(complete.cases(across(starts_with('score')))|row_number() == 1) %>%
ungroup
-输出
# A tibble: 4 × 3
name score1 score2
<chr> <dbl> <dbl>
1 justin 1 7
2 corey 2 5
3 sib 2 9
4 kate NA NA
您可以使用 fill()
,然后 arrange()
分数并使用 slice_head()
:
test_dataset %>%
group_by(name) %>%
fill(score1, score2) %>%
arrange(score1, score2) %>%
slice_head(n=1)
输出:
name score1_true score2_true
<chr> <dbl> <dbl>
1 justin 1 7
2 corey 2 5
3 sib 2 9
4 kate NA NA
更多concise/improved版本感谢@M.Viking:
- 在
fill()
中使用
.direction="up"
选项
test_dataset %>%
group_by(name) %>%
fill(score1, score2, .direction="up") %>%
slice_head(n=1)