R-汇总相对学期顺序的课程注册情况

时间:2019-04-25 19:25:55

标签: r dplyr sequence purrr

应用问题

我想抽象出一些代码,总结出 n 个课程和 n 个术语的学生的选课模式和成功率。

示例

在以下学生群体中,有多少人在修完“ A”课程后进入了“ B”课程, ,有多少学生获得了成功:

data <- data.frame(student = c(1, 1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5),
                   term    = c(2, 3, 3, 1, 2, 3, 2, 1, 3, 1, 2, 4),
                   course  = c('A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C', 'A', 'A', 'C'),
                   success = c(1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1),
                   stringsAsFactors = FALSE)

我们可以使用以下代码回答该问题:

library(dplyr) 

# Get each student's first, second, third, ... term.
    data <- data %>%
      group_by(student) %>%
      mutate(term_dense = dense_rank(term))%>%
      ungroup()

# Identify those who took course A
    courseA <- data %>%
      filter(course == "A")%>%
      select(student, courseA_dense = term_dense)

# Get records of students who took course A, and their subsequent courses
    data <- data %>%
      left_join(courseA, by = "student")%>%
      filter(term_dense >= courseA_dense) # >= for courses they took in same term as course "A"

# Summarise for each term_dense
    data %>%
      group_by(term_dense) %>%
      summarise(attempted_course_A = sum(course == "A"),
                completed_course_A = sum(course == "A" & success == 1),
                attempted_course_B = sum(course == "B"),
                completed_course_B = sum(course == "B" & success == 1))

哪个会产生:

# A tibble: 3 x 5
  term_dense attempted_course_A completed_course_A attempted_course_B completed_course_B
       <int>              <int>              <int>              <int>              <int>
1          1                  4                  2                  0                  0
2          2                  2                  2                  2                  2
3          3                  0                  0                  0                  0

我们可以看到尝试过课程A的学生中有2人尝试过课程B,两者均成功。

现在,我可以通过在summarise语句(即completed_course_C = sum(course == "C" & success == 1))中添加行来计算在修完课程“ A”之后修过课程“ C” 的人数,但是如果我有很多课程,这似乎不是最有效的选择。

此外,如果我想总结课程“ Y”之后的课程“ X” ,对于任何“ X”和“ Y”,它会创建{{1}的更多排列}语句。而我该如何看待那些在“ Z”之后的“ X” “ Y”

那么,我如何总结可变数量,不同学期的课程的课程进度和成功率?

所需的输出

我认为这就是我的一些困难所在。我不知道结果summarise的结构应该是什么样的。

我确实知道我想轻松回答以下一般问题:

“在课程“ A”中成功的学生中有X%的学生随后在课程“ B”中获得了Y%的成功率”

抽象问题

我一直在尝试将一般性问题(群组跟踪/排序?)应用于其他领域,以便在Google和Stack Overflow中获得更好的关键字/搜索结果。似乎很有前途的一种方法是使用网络分析。

特别是this post, Network Analysis with R,有助于确定潜在的解决方案。我按照本文进行操作,改用我的数据,并能够获取大约一半的信息。使用这种方法,我只能获得一系列尝试或一系列成功率,而不能同时获得。但是我才刚刚开始学习网络分析。

实际上,我已经能够使用plotly's sankey diagram手动显示摘要,该摘要使用类似的网络/链接框架。但是我仍然无法以编程方式计算该信息。

其他尝试

鉴于我实际上想将摘要函数“映射”到我的数据,因此我的许多尝试都使用了带有嵌套列表列的data.frame包。

purrr次尝试

我使用上方的原始purrr,尝试根据排名的学生嵌套课程列表。

data

然后,我尝试创建一个函数,该函数将源课程的摘要返回到目标课程,最终目标是# library(dplyr) # Loaded in above example library(tidyr) library(purrr) data <- data %>% group_by(student) %>% mutate(term_dense = dense_rank(term)) %>% ungroup()%>% nest(term, course, success, .key = "schedule") 将该函数复制到包含源和目标的所有唯一排列的列表中:

map

该功能仅适用于一个示例,

attempt_summary <- function(df, source, target){

  temp_df <- df %>%
                filter(map_lgl(schedule, ~any(.x$course == source)))%>%
                select(student, source_term_dense = term_dense)

  df <- df %>%
        left_join(temp_df, by = "student")%>%
        filter(term_dense >= source_term_dense)

  df %>%
    group_by(term_dense) %>%
    summarise(completed_source = sum(map_int(schedule, ~any(.x$course == source & .x$success == 1))),
              attempted_target = sum(map_int(schedule, ~any(.x$course == target))),
              completed_target = sum(map_int(schedule, ~any(.x$course == target & .x$success == 1))))

}

但是我不知道如何将其映射到其他所有内容(我什至不知道如何构建目标列表和源列表),但这是我的尝试:

attempt_summary(data, "A", "B")

# A tibble: 3 x 4
  term_dense completed_source attempted_target completed_target
       <int>            <int>            <int>            <int>
1          1                2                0                0
2          2                2                2                2
3          3                0                0                0

堆栈溢出帖子

除了关于# DO NOT RUN - DOESN'T WORK # map(data, attempt_summary, source = src_list, target = trgt_list) 的许多其他文章之外,我在寻找解决方案时还引用了这些帖子,但我所寻找的都不是。

会话信息

这是我的purrr通话的输出:

sessionInfo()

1 个答案:

答案 0 :(得分:0)

在您的问题中间,只有一小部分关于“在课程A中成功的X%学生,随后在课程B中获得Y%的成功率”。

这将找到每门课程A成功和每门课程A不成功的Y%。

library(tidyverse)
data2 <- data %>%
  left_join(data, by = c("student")) %>%   # add future course results to each result that has any
  filter(term.y > term.x) %>%  # includes all future courses; could limit to just next one?
  count(course.x, success.x, course.y, success.y) %>%
  spread(success.y, n, fill = 0) %>%
  mutate(success_rate = `1`/ (`0` + `1`)) %>%
  select(course.x:course.y, success_rate) %>%
  spread(course.y, success_rate)

结果:每行“事件1”,以及每列中将来Y类的成功率。这表明,修读A的人通过了所有后续课程,无论他们在A中的成绩如何。修读B的人在C上的通过率均为50-50。

> data2
# A tibble: 3 x 5
  course.x success.x     A     B     C
  <chr>        <dbl> <dbl> <dbl> <dbl>
1 A                0     1    NA   1  
2 A                1    NA     1   1  
3 B                1    NA    NA   0.5