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

如何用R(Base或dplyr)筛选英数测试间隔≤30天的学生

筛选英数测试间隔小于30天的学生:报错修复方案

现有包含student_id、date、test三个字段的数据集,需求是筛选出存在任意英语(english)测试与数学(math)测试间隔小于30天的学生(测试先后顺序不影响)。运行GPT提供的dplyr代码时触发如下报错:

Error: Problem with mutate() column diff.
i diff = abs(...).
i diff must be size 3 or 1, not 2.
i The error occurred in group 1: student_id = "A".

数据集代码

df <- data.frame(student_id = c("A", "C", "A", "B", "C", "B", "C", "C", "B", "A", "A"),
                 date = as.Date(c("2022-01-02", "2022-05-02", "2022-04-07", "2022-03-09", "2022-04-02", "2022-04-02", "2022-03-16", "2022-03-01", "2022-05-10", "2022-01-17", "2022-04-02")),
                 test = c("english", "science", "math", "english", "math", "science", "english", "math", "math", "math", "science"))

报错原因

原代码的核心问题是:当单个学生有多条英语或数学测试记录时,date[test == "english"]和date[test == "math"]返回的向量长度不匹配,导致difftime计算出的时间差数量与当前分组的行数不一致。比如学生A有1条英语记录、2条数学记录,计算后会得到2个时间差,但分组后当前行有3条(1英+2数),mutate要求生成的diff列长度必须和行数完全一致,因此触发维度错误。

修复方案

以下两种方法均可实现需求,且能避免维度不匹配问题:

方法1:宽表化后生成所有英数日期组合

先将数据转换为宽表格式,给同一学生的同类型测试记录编号,再生成所有英语与数学日期的组合,最后筛选间隔小于30天的学生:

library(dplyr)
library(tidyr)

df_filtered <- df %>%
  # 只保留英语和数学测试记录
  filter(test %in% c("english", "math")) %>%
  # 给同一学生的同类型测试记录编序号,避免宽表化时丢失数据
  mutate(row_id = row_number(), .by = c(student_id, test)) %>%
  # 转换为宽表,英语和数学日期分别作为列
  pivot_wider(names_from = test, values_from = date) %>%
  # 生成当前学生所有英语与数学日期的组合
  expand_grid(english, math, .by = student_id) %>%
  # 计算时间差的绝对值(单位:天)
  mutate(diff = abs(as.numeric(difftime(english, math, units = "days")))) %>%
  # 筛选间隔小于等于30天的记录
  filter(diff <= 30) %>%
  # 提取去重后的学生ID
  select(student_id) %>%
  distinct()

方法2:分组后生成测试记录两两组合

在学生分组内生成所有测试记录的两两组合,筛选出英语与数学的配对,再判断时间间隔:

library(dplyr)

df_filtered <- df %>%
  # 只保留英语和数学测试记录
  filter(test %in% c("english", "math")) %>%
  # 按学生分组
  group_by(student_id) %>%
  # 生成当前学生所有测试记录的两两组合
  cross_join(., ., suffix = c("_x", "_y")) %>%
  # 排除同类型测试的组合(如英语和英语、数学和数学)
  filter(test_x != test_y) %>%
  # 计算时间差的绝对值(单位:天)
  mutate(diff = abs(as.numeric(difftime(date_x, date_y, units = "days")))) %>%
  # 筛选间隔小于等于30天的记录
  filter(diff <= 30) %>%
  # 提取去重后的学生ID
  select(student_id) %>%
  distinct() %>%
  # 取消分组
  ungroup()

结果验证

运行上述代码后,会得到符合条件的学生ID:A和C。其中:

  • 学生A的英语测试(2022-01-02)与数学测试(2022-01-17)间隔15天,满足条件;
  • 学生C的英语测试(2022-03-16)与数学测试(2022-03-01)间隔15天,满足条件;
  • 学生B的英语测试与所有数学测试间隔均超过30天,被排除。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 19:23:11