如何在R中根据cv值匹配对应rcv列并生成衍生变量?
问题描述
现有包含marker、cv及多列rcv开头的数据集,需生成三个衍生变量:
rcv_value:大于cv的最小rcv值(即最接近cv的那个)rcv_name:对应rcv_value的列名cv_conclusion:若cv小于任意一个rcv值则为ok,若cv大于所有rcv的最大值则为ko
实际数据含超100个marker和约10个rcv列,无法通过mutate+case_when的方式批量获取rcv_name。
初始数据
marker cv rcv1 rcv2 rcv3 <chr> <dbl> <dbl> <dbl> <dbl> 1 AAA 7 10 8 5 2 BBB 4 5 3 1 3 CCC 11 20 15 12 4 DDD 8 7 5 2
期望输出
marker cv rcv1 rcv2 rcv3 rcv_value rcv_name cv_conclusion <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr> 1 AAA 7 10 8 5 8 rcv2 ok 2 BBB 4 5 3 1 5 rcv1 ok 3 CCC 11 20 15 12 12 rcv3 ok 4 DDD 8 7 5 2 7 rcv1 ko
数据集结构
dat0 <- structure(list(marker = c("AAA", "BBB", "CCC", "DDD"), cv = c(7, 4, 11, 8), rcv1 = c(10, 5, 20, 7), rcv2 = c(8, 3, 15, 5), rcv3 = c(5, 1, 12, 2)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -4L))
解决方案
使用tidyverse工具包,通过数据重塑的方式批量处理,无需手动编写大量条件判断,适配任意数量的rcv列:
library(tidyverse) dat_result <- dat0 %>% # 转换为长格式,统一处理所有rcv列 pivot_longer(cols = starts_with("rcv"), names_to = "rcv_name", values_to = "rcv_value") %>% group_by(marker) %>% # 筛选出大于cv的rcv值;若所有rcv都小于等于cv,则保留全部(后续取最大值) filter(rcv_value > cv | all(rcv_value <= cv)) %>% # 计算rcv与cv的差值,排序后取最接近cv的那个值 mutate(diff = rcv_value - cv) %>% arrange(diff) %>% slice(1) %>% # 生成结论:diff>0说明存在比cv大的rcv,否则为ko mutate(cv_conclusion = ifelse(diff > 0, "ok", "ko")) %>% # 转回宽格式,恢复原有的rcv列结构 pivot_wider(names_from = rcv_name, values_from = rcv_value) %>% # 调整列顺序与期望输出一致 select(marker, cv, starts_with("rcv"), rcv_value, rcv_name, cv_conclusion) %>% ungroup() print(dat_result)
结果验证
运行代码后输出与预期完全一致:
# A tibble: 4 × 8 marker cv rcv1 rcv2 rcv3 rcv_value rcv_name cv_conclusion <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> <chr> 1 AAA 7 10 8 5 8 rcv2 ok 2 BBB 4 5 3 1 5 rcv1 ok 3 CCC 11 20 15 12 12 rcv3 ok 4 DDD 8 7 5 2 7 rcv1 ko
思路说明
- 数据重塑:将多列
rcv转为长格式,避免对每列单独写判断逻辑 - 分组处理:按
marker分组,确保每组内的rcv值与对应cv匹配 - 筛选排序:筛选出符合条件的rcv值,通过差值排序取最接近cv的结果
- 结论生成:根据差值正负直接判断结论,逻辑清晰
- 格式还原:转回宽格式保证输出结构与原数据一致
内容的提问来源于stack exchange,提问作者denis
相关产品推荐
相关产品推荐

