R按标识符合并列

R coalesce down columns by identifer

我有一个很长的数据集,其中包含跨多个学期的学生成绩和课程。每个学生都有很多 NA 和很多行。我希望每个学生都有一长行来填写那些 NA,但保留相同的列名。

这是一个示例:

library(tidyverse)
sample <- tibble(student = c("Corey", "Corey", "Sibley", "Sibley"),
                 fall_course_1 = c("Math", NA, "Science", NA),
                 fall_course_2 = c(NA, "English", NA, NA),
                 fall_grade_1 = c(90, NA, 98, NA),
                 fall_grade_2 = c(NA, 60, NA, NA))

我希望它看起来像这样:

library(tidyverse)
answer <- tibble(student = c("Corey", "Sibley"),
                 fall_course_1 = c("Math", "Science"),
                 fall_course_2 = c("English", NA),
                 fall_grade_1 = c(90, 98),
                 fall_grade_2 = c(60, NA))

有些学期,有些学生选了很多 类,有些只选了一个。我试过使用 coalesce(),但我想不通。如有任何帮助,我们将不胜感激!

使用自定义 colaesce 函数和 dplyr:

coalesce_all_columns <- function(df) {
  return(coalesce(!!! as.list(df)))
}

library(dplyr)

sample %>%
  group_by(student) %>%
  summarise_all(coalesce_all_columns)

# A tibble: 2 x 5
  student fall_course_1 fall_course_2 fall_grade_1 fall_grade_2
  <chr>   <chr>         <chr>                <dbl>        <dbl>
1 Corey   Math          English                 90           60
2 Sibley  Science       NA                      98           NA

您可以获得每个 student 的每列中的第一个非 NA 值。

library(dplyr)
sample %> group_by(student) %>% summarise_all(~na.omit(.)[1])

# A tibble: 2 x 5
#  student fall_course_1 fall_course_2 fall_grade_1 fall_grade_2
#  <chr>   <chr>         <chr>                <dbl>        <dbl>
#1 Corey   Math          English                 90           60
#2 Sibley  Science       NA                      98           NA

如果一个组中有所有 NA 个值,则此方法 returns NA

应该这样做,旋转长数据,删除 na,然后将其旋转回宽数据。

您需要暂时将数值转换为字符,以便它们可以与课程标签放在同一列中,然后 type_convert() 是一种懒惰的方法,可以将它们再次放回去。

library(dplyr)
library(tidyr)
library(readr)

reshaped <- sample %>%
  mutate_if(is.numeric, as.character) %>%
  pivot_longer(-student) %>% 
  drop_na() %>% 
  pivot_wider(student, names_from = name, values_from = value) %>% 
  type_convert()

您也可以使用 data.table 包如下:

library(data.table)
setDT(sample)[, lapply(.SD, na.omit), student]

sample
# 1:   Corey          Math       English           90           60
# 2:  Sibley       Science          <NA>           98           NA