You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言:基于日期范围使用mutate生成大学学期列的问题求助

问题分析

你的代码出现大量NA且学期判断错误,核心原因有两个:

  1. 未锚定入学基准日期:原代码用enroll_begin的自然年偏移计算区间,而非以学生首次入学日期作为第1学期的起点,导致学期判断完全偏离实际入学时间线。
  2. 区间规则不匹配:原代码的日期区间与你给出的院校学期起始(如2016-09-01为第1学期、2017-01-09为第2学期)完全不符,且部分日期落在所有区间之外,产生大量NA。
解决方案

以下提供两种实现方式,既解决当前问题,又支持不同院校的自定义学期规则。

方式1:封装通用函数(支持多学生/多院校)

此函数以学生首次入学日期为锚点,可自定义学期起始月日,适配不同院校的学期划分:

library(dplyr)
library(lubridate)
library(purrr)

assign_semester <- function(df, date_col = "enroll_begin", semester_starts = list(
  first = c(month = 9, day = 1),  # 第1学期起始月日
  second = c(month = 1, day = 9)  # 第2学期起始月日
)) {
  df %>%
    group_by(sid) %>%  # 按学生分组,确保每个学生的学期从自身入学日开始计算
    mutate(
      # 获取当前学生的首次入学日期(第1学期起点)
      first_enroll = min(!!sym(date_col)),
      enroll_year = year(first_enroll),
      # 自动生成10个学期的起始/结束日期(可调整数量)
      semesters = list(tibble(
        semester_num = seq(1, 10),
        start_date = case_when(
          # 奇数学期:秋季学期,起始月日为first参数
          semester_num %% 2 == 1 ~ ymd(paste0(enroll_year + (semester_num-1)%/%2, "-", semester_starts$first["month"], "-", semester_starts$first["day"])),
          # 偶数学期:春季学期,起始月日为second参数
          semester_num %% 2 == 0 ~ ymd(paste0(enroll_year + (semester_num-2)%/%2, "-", semester_starts$second["month"], "-", semester_starts$second["day"]))
        ),
        # 每个学期的结束日期为下一个学期的前一天
        end_date = lead(start_date) - days(1)
      ) %>% mutate(end_date = ifelse(is.na(end_date), first_enroll + years(4), end_date))),  # 最后一个学期默认设为入学后4年结束
      # 匹配每个入学日期对应的学期
      semester = map_chr(!!sym(date_col), ~{
        sem_df <- semesters[[1]]
        match_idx <- which(.x >= sem_df$start_date & .x <= sem_df$end_date)
        if(length(match_idx) > 0) {
          paste0(c("first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth")[match_idx], " semester")
        } else {
          NA_character_
        }
      })
    ) %>%
    ungroup() %>%
    select(-first_enroll, -enroll_year, -semesters)  # 移除中间变量
}

# 应用到测试数据集
test_data_fixed <- assign_semester(test_data)

# 查看结果
test_data_fixed %>% select(enroll_begin, semester)

函数说明

  • 若其他院校的学期起始不同,只需修改semester_starts参数即可,例如某院校春季学期从1月15日开始,传入semester_starts = list(first = c(9,1), second = c(1,15))。
  • 自动生成的学期数量可通过seq(1,10)调整,比如改为seq(1,8)支持8个学期。

方式2:简化版(仅针对当前测试数据)

如果只需要处理当前数据集,可直接手动定义学期区间:

test_data %>%
  mutate(
    semester = case_when(
      enroll_begin >= ymd("2016-09-01") & enroll_begin <= ymd("2017-01-08") ~ "first semester",
      enroll_begin >= ymd("2017-01-09") & enroll_begin <= ymd("2017-06-30") ~ "second semester",
      enroll_begin >= ymd("2017-07-01") & enroll_begin <= ymd("2018-01-08") ~ "third semester",
      enroll_begin >= ymd("2018-01-09") & enroll_begin <= ymd("2018-06-30") ~ "fourth semester",
      enroll_begin >= ymd("2018-07-01") & enroll_begin <= ymd("2019-01-08") ~ "fifth semester",
      enroll_begin >= ymd("2019-01-09") & enroll_begin <= ymd("2019-06-30") ~ "sixth semester",
      enroll_begin >= ymd("2019-07-01") & enroll_begin <= ymd("2020-01-08") ~ "seventh semester",
      enroll_begin >= ymd("2020-01-09") & enroll_begin <= ymd("2020-06-30") ~ "eighth semester",
      enroll_begin >= ymd("2020-07-01") & enroll_begin <= ymd("2021-01-08") ~ "ninth semester",
      enroll_begin >= ymd("2021-01-09") & enroll_begin <= ymd("2021-06-30") ~ "tenth semester",
      TRUE ~ NA_character_
    )
  )

内容的提问来源于stack exchange,提问作者Shannon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 10:37:02