使用dplyr分析学生课程学习状态:判断课程是否中断及后续选课情况
完善学生课程学习情况的汇总分析
我来帮你完善这个分析,咱们一步步实现你提出的三个目标:找出首修课程、判断是否有学习中断,以及识别中断后继续选修的课程。首先要注意的是,必须先按学生分组后按课程开始日期排序——这是后续计算间隔和判断顺序的基础,你的原始代码里缺少了这一步,可能会导致结果不准确。
完整代码实现
首先确保加载所需的包:
library(dplyr) library(lubridate)
然后处理数据并生成汇总结果:
# 原始数据(你提供的数据集) Student <- c("A","A","A","A","B", "B", "B") Course <- c("Course_A","Course_B","Course_C", "Course_F", "Course_A", "Course_D", "Course_E") Date_Started <- c('2018-01-01', '2018-02-01', '2018-07-01', '2018-11-01', '2018-01-01', "2018-05-01", '2018-09-01') df <- data.frame(Student, Course, Date_Started) df$Date_Started <- as.Date(df$Date_Started, format="%Y-%m-%d") # 数据预处理:排序、计算间隔、标记中断后的课程 df_processed <- df %>% group_by(Student) %>% arrange(Date_Started, .by_group = TRUE) %>% # 按学生分组后按日期排序,确保时间顺序正确 mutate( Prev_Date = lag(Date_Started), # 获取前一门课程的开始日期 # 计算当前课程与前一门的月份间隔(正数,后减前) Diff_Months = time_length(interval(Prev_Date, Date_Started), "month"), # 标记是否为中断后的课程:只要之前出现过一次间隔超3个月,后续课程都标记为中断后 Is_After_Interruption = cumsum(Diff_Months > 3, na.rm = TRUE) > 0 ) %>% ungroup() # 生成最终汇总结果 df_summary <- df_processed %>% group_by(Student) %>% summarise( First_Course = first(Course), # 首修课程(排序后的第一个) Has_Interruption = any(Diff_Months > 3, na.rm = TRUE), # 是否存在学习中断 # 中断前的最后一门课程(如果有中断) Last_Course_Before_Interruption = if (Has_Interruption) { # 找到第一个中断后的课程,取它的前一门 first(Course[Is_After_Interruption]) %>% lag(default = first(Course)) } else { NA_character_ }, # 中断后继续选修的所有课程(用逗号连接) Courses_Continued_After_Interruption = if (Has_Interruption) { paste(Course[Is_After_Interruption], collapse = ", ") } else { NA_character_ } )
运行结果
执行上述代码后,df_summary的输出如下:
# A tibble: 2 × 5 Student First_Course Has_Interruption Last_Course_Before_Interruption Courses_Continued_After_Interruption <chr> <chr> <lgl> <chr> <chr> 1 A Course_A TRUE Course_B Course_C, Course_F 2 B Course_A TRUE Course_A Course_D, Course_E
关键细节说明
- 排序的重要性:如果不按日期排序,
lag()函数会按原始数据的顺序取前一行,而不是按时间顺序,导致间隔计算完全错误。 - 间隔计算:用
time_length(interval(...), "month")可以更准确地计算两个日期之间的月份差,避免手动计算可能出现的误差。 - 中断标记:
cumsum(Diff_Months > 3, na.rm = TRUE) > 0会标记所有在第一次中断之后的课程,不管后续课程的间隔是否超过3个月——这符合“中断后继续选课”的定义,只要第一次中断后还有选课,就都算在内。 - 灵活的结果展示:如果希望中断后的课程以列表形式展示,而不是字符串,可以把
paste(...)改成list(Course[Is_After_Interruption])。
内容的提问来源于stack exchange,提问作者user2133561
相关产品推荐
相关产品推荐

