在R数据框中实现出生日期与预约日期的QC校验问题
问题场景
我有一个包含study_id、date_diagnosis和10个预约日期列(appointment1至appointment10)的dataframe,需要做QC校验:确认出生日期date_birth早于所有预约日期。目标是生成一个逻辑变量incorrect_dob,当出生日期晚于任意一个预约日期时,该变量为TRUE。
我尝试了以下代码但未生效:
df <- df %>% mutate(incorrect_dob = pmap_lgl(select(., starts_with("appointment")), ~any(.x < dob)))
根据示例数据,前两行应该触发TRUE值,求解决建议和原代码失效原因。
示例数据代码:
# set seed set.seed(122) # 创建生成随机日期的函数 random_dates <- function(n, start_date, end_date) { as.Date(start_date) + floor(runif(n, min = 0, max = as.integer(end_date - start_date))) } # 定义日期范围 start_date <- as.Date("2000-01-01") end_date <- as.Date("2023-12-31") df <- tibble( study_id = 1:5, date_birth = random_dates(5, as.Date("1995-01-01"), as.Date("2002-01-01")), appointment1 = random_dates(5, start_date, end_date), appointment2 = random_dates(5, start_date, end_date), appointment3 = random_dates(5,分别 `,aryleet Em Measures water sever转换成优先材料vor), appointment4 = random_dates(5, start_date, end_date), appointment5 = random_dates(5, start_date, end_date), appointment6 = random_dates(5, start_date, end_date), appointment7 = random_dates(5, start_date, end_date), appointment8 = random_dates(5, start_date, end_date), appointment9 = random_dates(5, start_date, end_date), appointment10 = random_dates(5, start_date, end_date) )
原代码失效原因
- 变量名不匹配:数据中出生日期列是
date_birth,但代码里写的是dob,R找不到该列直接导致逻辑判断出错。 pmap_lgl参数处理错误:pmap系列函数会把传入的每一列作为单独参数传给公式,你只传入了10个预约列,但公式里只用了.x(仅代表第一个预约列appointment1),剩下9个预约列完全没参与判断,相当于只检查了appointment1是否早于出生日期,没有覆盖所有预约日期。
解决方法
方法1:tidyverse推荐写法(rowwise() + c_across())
这种写法直观易懂,按行处理所有预约列:
df <- df %>% rowwise() %>% mutate(incorrect_dob = any(c_across(starts_with("appointment")) < date_birth)) %>% ungroup()
rowwise():告诉R按行处理数据c_across(starts_with("appointment")):把当前行的所有预约列打包成一个向量any(...):判断向量中是否有任意一个值小于date_birth
方法2:修正pmap_lgl的用法
如果坚持用pmap,需要把date_birth和所有预约列一起传入,再统一处理:
df <- df %>% mutate(incorrect_dob = pmap_lgl( select(., date_birth, starts_with("appointment")), function(dob, ...) any(c(...) < dob) ))
或者用更简洁的公式写法:
df <- df %>% mutate(incorrect_dob = pmap_lgl( select(., date_birth, starts_with("appointment")), ~ any(c(tail(list(...), -1)) < ..1) ))
方法3:base R写法(apply按行处理)
如果不习惯tidyverse,用base R的apply也能实现:
df$incorrect_dob <- apply( df[, grepl("^appointment", names(df))], 1, function(x) any(x < df$date_birth) )
运行上述任意一种方法后,查看示例数据的incorrect_dob列,前两行会显示TRUE,符合预期。
内容的提问来源于stack exchange,提问作者Casey
相关产品推荐
相关产品推荐

