R语言 为什么map_df会产生很多缺失值?我如何跨行连接以删除NA?

p8h8hvxi  于 2023-01-28  发布在  其他
关注(0)|答案(2)|浏览(136)

我试图计算有多少学生在他们的科目中得到了1、2、3、4和5,我希望为每门科目和可能的分数(math_1、science_2等)设置一列。
我最初写了一个for循环,但是我的实际数据集有太多的case,我需要使用map。我可以让它工作,但是它产生了许多NA,并且每列只有一个块有实际数据。我很好奇地想知道:
1.为什么map_df()会这样做?如何避免?或者
1.我怎样才能把这个数据集中起来,使第一个数据集中的原始行(18行)中只有一行有这个信息?换句话说,我将上下连接列,这样所有的NA都被填充了(除非真的有缺失数据)。
这是我的密码

library(tidyverse)

#Set up - generate sample dataset and get all combinations of grades and subjects

student_grades <- tibble(student_id = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5),
                         subject = c(rep(c("english", "biology", "math", "history"), 4), NA, "biology"),
                         grade = as.character(c(1, 2, 3, 4, 5, 4, 3, 2, 2, 4, 1, 1, 1, 1, 2, 3, 3, 4)))

all_subject_combos <- c("english", "history", "math", "biology")
all_grades <- c("1", "2", "3", 
                "4", "5")

subjects_and_letter_grades <- expand.grid(all_subject_combos, all_grades)

all_combos <- subjects_and_letter_grades %>%
  unite("names", c(Var1, Var2)) %>%
  mutate(names = str_replace_all(names, "\\|", "_")) %>%
  pull(names)

# iterate over each combination using map_df()
student_map <- map_df(all_combos,
                        ~student_grades %>%
                          mutate("{.x}" := paste(i)) %>%
                          group_by(student_id) %>%
                          mutate("{.x}" := sum(case_when(str_detect(.x, subject) &
                                                           str_detect(.x, grade) ~ 1,
                                                         TRUE ~ 0), na.rm = T)))

EDIT声明一下,我几乎相同的for循环并没有填充很多缺失的值,我认为这一定与构建数据集的方式有关,但我不知道如何覆盖map_df在幕后所做的事情。

student_map <- student_grades
for(i in all_combos) {
  student_map <- student_map %>%
    mutate("{i}" := paste(i)) %>%
    group_by(student_id) %>%
    mutate("{i}" := sum(case_when(str_detect(i, subject) &
                                    str_detect(i, grade) ~ 1,
                                  TRUE ~ 0), na.rm = T)) 
}
332nm8kg

332nm8kg1#

map中没有i,因为循环的默认lambda值是.x。此外,最好使用transmute而不是mutate,因为我们只需要返回在每次迭代中添加的列,然后在最后绑定原始数据

library(dplyr)
library(purrr)
library(stringr)
student_map2 <- map_dfc(all_combos,
  ~ student_grades %>% 
  transmute(subject, grade, student_id, "{.x}" := .x) %>% 
  group_by(student_id) %>%  
  transmute("{.x}" := sum(case_when(str_detect( .x, subject) & 
      str_detect(.x, grade)~ 1, TRUE ~ 0), na.rm = TRUE)) %>%
  ungroup %>% 
  select(-student_id)) %>% 
   bind_cols(student_grades, .)
  • 用OP检查回路输出
> all.equal(student_map, student_map2, check.attributes = FALSE)
[1] TRUE
tf7tbtn2

tf7tbtn22#

虽然我不明白map_df()为什么会以这种不受欢迎的方式执行,但我确实找到了一个解决方案,这主要是受answer to this post的启发。

solution <- student_map %>% 
  group_by(student_id, subject, grade) %>%
  summarise_all(~ last(na.omit(.)))

solution

基本上,这段代码删除了所有的NA,并且只在只有缺失值的情况下保留缺失值,因为我的数据集中的那些列永远不会有缺失值,所以这个解决方案在我的情况下是有效的。

相关问题