R中按优先级比对成对列最大值并批量生成选中列的方法
问题背景
我一直尝试用循环实现需求但始终无法成功,此前没有处理过这类复杂场景,尝试用dplyr解决也没有进展,希望大家能提供可行方案,感谢。
数据特征
- 包含成对列A_1、A_2、B_1、B_2、C_1、C_2、D_1、D_2、E_1、E_2、F_1、F_2、G_1、G_2……等,共1000行。
示例数据
dat <- read.table(text = "ID A_1 A_2 B_1 B_2 C_1 C_2 D_1 D_2 E_1 E_2 F_1 F_2 G_1 G_2 11 1 2 3 4 3 4 3 4 3 4 3 4 3 4 32 5 6 7 8 6 7 6 7 6 7 6 7 6 7 73 15 15 10 10 3 4 3 4 3 4 3 4 2 2 84 13 13 15 15 4 4 3 4 3 4 3 4 2 2 65 2 2 2 2 2 2 2 2 2 2 2 1 2 2 ", header = TRUE)
需求详情
- 首先比对A_1和A_2,取较大值,将最大值存入
selected_[列名]_val列,对应列名存入selected_[列名]_name列,后续所有B、C等成对列统一取后缀和A的最大列一致的列(例如A_2更大就全取_2后缀的列,生成对应的selected列)。 - 如果A_1等于A_2,则比对B_1和B_2,取较大值后,后续所有成对列统一取和B的最大列后缀一致的列,生成对应selected列。
- 如果B_1也等于B_2则继续比对C_1和C_2,以此类推。
- 如果所有成对列都相等,则默认取所有_1后缀的列。
补充说明
整行所有成对列选_1还是_2都由第一个出现两个值不等的终止列的后缀决定。
解决方案
可以结合tidyverse的行遍历逻辑实现,代码如下:
# 加载依赖包 library(tidyverse) # 提取所有成对列的公共前缀(排除ID列,支持多字母前缀) prefixes <- str_extract(names(dat)[-1], "^[A-Za-z]+(?=_)") %>% unique() dat_result <- dat %>% # 按行处理 rowwise() %>% mutate( # 确定当前行要取的后缀,默认值为1 target_suffix = { res <- 1 # 按顺序遍历所有前缀比对_1和_2的值 for (p in prefixes) { v1 <- get(paste0(p, "_1")) v2 <- get(paste0(p, "_2")) if (v1 != v2) { res <- ifelse(v1 > v2, 1, 2) break } } res }, # 批量生成selected_xxx_val列,存储对应后缀的取值 across( .cols = all_of(paste0(prefixes, "_", target_suffix)), .names = "selected_{str_remove(.col, '_.$')}_val" ), # 批量生成selected_xxx_name列,存储对应列名 across( .cols = all_of(prefixes), .fn = ~paste0(cur_column(), "_", target_suffix), .names = "selected_{.col}_name" ) ) %>% # 取消行分组 ungroup()
运行代码后得到的dat_result就包含所有需要的衍生列,完全匹配需求逻辑。
内容的提问来源于stack exchange,提问作者mgtrek
相关产品推荐
相关产品推荐

