如何判断Type为New的A年ID是否存在于A+1和A+3年份?
问题解决:判断新生ID在后续年份的存在性
问题描述
我有一个包含ID、ANNO(年份)、COD_CARRERA(专业ID)、TIPO_ALU(学生类型,取值为"NUEVO"或"old")、ANNO_RET_1(入学后第1年)、ANNO_RET_3(入学后第3年)的DataFrame,需要为TIPO_ALU="NUEVO"的ID新增两列:
- 判断该ID是否存在于
ANNO_RET_1对应的年份数据中 - 判断该ID是否存在于
ANNO_RET_3对应的年份数据中
我之前尝试编写了检查存在性的函数:
check_presence_1 <- function(BBDD2, ANNO) { BBDD2 %>% select(ID) %>% filter(ANNO == ANNO_RET_1) %>% mutate(present = TRUE) }
(类似地写了check_presence_3函数),随后用以下代码新增列,但得到无意义的结果:
result_data <- BBDD2 %>% filter(TIPO_ALU == "NUEVO") %>% mutate(first_year = min(ANNO), present_x1 = ifelse(ID %in% check_presence_1(filter(., ANNO > first_year), ANNO_RET_1)$ID, TRUE, FALSE), present_x3 = ifelse(ID %in% check_presence_3(filter(., ANNO > first_year), ANNO_RET_3)$ID, TRUE, FALSE))
我很久没使用R,寻求正确解决方案。
附数据样本:
structure(list(ANNO = c(2012, 2012, 2012, 2012, 2012), ID = c(14L, 37L, 76L, 100L, 112L), TIPO_ALU = c("NUEVO", "NUEVO", "NUEVO", "NUEVO", "NUEVO"), COD_CARRERA = c("I70S1C751J1V1", "I70S1C756J2V1", "I70S1C603J1V1", "I70S1C779J2V1", "I70S1C611J1V1"), ANNO_RET_1 = c(2013, 2013, 2013, 2013, 2013), ANNO_RET_3 = c(2015, 2015, 2015, 2015, 2015)), row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame" ))
期望新增列示例:PRESENT_ANNO+1 = c(1, 1, 0, 1, 0),PRESENT_ANNO+3 = c(0, 1, 0, 0, 0)
问题分析
原代码的核心问题:
- 函数中
filter(ANNO == ANNO_RET_1)存在变量名冲突,函数参数ANNO与数据列ANNO重名,导致筛选逻辑完全错误 mutate中first_year = min(ANNO)取的是整个筛选后数据集的最小年份,而非每个ID对应的入学年份,逻辑不符合需求- 调用检查函数时的参数传递逻辑混乱,没有正确关联每个ID对应的
ANNO_RET_1/ANNO_RET_3年份
正确解决方案
方法一:预先生成年份-ID映射表(高效版)
先整理出每个年份下存在的ID集合,再对新生数据做匹配,适合大数据量场景:
library(dplyr) # 1. 生成年份-ID映射表:存储每个年份对应的所有ID year_id_map <- BBDD2 %>% group_by(ANNO) %>% summarise(existing_ids = list(ID), .groups = "drop") # 2. 处理新生数据,新增存在性列 result_data <- BBDD2 %>% filter(TIPO_ALU == "NUEVO") %>% # 匹配入学后第1年的ID集合 left_join(year_id_map, by = c("ANNO_RET_1" = "ANNO")) %>% mutate(PRESENT_ANNO_plus_1 = as.integer(ID %in% unlist(existing_ids))) %>% select(-existing_ids) %>% # 匹配入学后第3年的ID集合 left_join(year_id_map, by = c("ANNO_RET_3" = "ANNO")) %>% mutate(PRESENT_ANNO_plus_3 = as.integer(ID %in% unlist(existing_ids))) %>% select(-existing_ids)
代码说明
year_id_map:通过group_by+summarise生成每个年份对应的ID列表,后续可快速查找left_join:将新生的ANNO_RET_1/ANNO_RET_3与映射表关联,获取目标年份的所有IDas.integer(...):将逻辑判断结果转为0/1数值,匹配期望的输出格式
方法二:逐行直接检查(简洁版)
如果数据量不大,可直接用rowwise()逐行验证,代码更简洁:
library(dplyr) result_data <- BBDD2 %>% filter(TIPO_ALU == "NUEVO") %>% rowwise() %>% mutate( PRESENT_ANNO_plus_1 = as.integer(any(BBDD2$ANNO == ANNO_RET_1 & BBDD2$ID == ID)), PRESENT_ANNO_plus_3 = as.integer(any(BBDD2$ANNO == ANNO_RET_3 & BBDD2$ID == ID)) ) %>% ungroup()
代码说明
rowwise():让后续的mutate逐行处理每个IDany(...):直接检查当前ID是否在目标年份的数据集里,返回逻辑值后转为0/1
内容的提问来源于stack exchange,提问作者TDaneri
相关产品推荐
相关产品推荐

