如何在R的dplyr中获取指定列的行最小值及对应列名后缀
问题与解决方案
数据集
library(dplyr) Data <- tibble(Code = letters[1:6], Min_0 = c(12.3, NA, 1.1, NA, 0, NA), Min_1 = c(3.6, NA, 12.4, 1.7, 15.6, NA), Min_2 = c(45.6, NA, 2.4, 28.9, 32.7, NA), Min_3 = c(2.3, NA, NA, NA, NA, NA), Min_4 = c(52.4, NA, 23.6, 4.6, 0, NA), Min_5 = c(0, NA, 5.7, NA, 0.1, NA))
需求
需要为每行添加两列:
- Min_Time:取
Min_1至Min_5列中的最小值,若这些列全为NA则设为NA; - Min_ID:取对应最小值所在列名的最后一位数字,示例输出如下:
Data %>% mutate(Min_ID = c(5, NA, 2, 1, 4, NA))
已实现部分(Min_Time)
已通过自定义函数实现Min_Time的计算,代码如下:
Min_Function <- function(x, f, ...) ifelse(all(is.na(x)), NA, ifelse(all(is.na(x)), 0, f(x[x >= 0], na.rm = TRUE, ...))) Data %>% rowwise() %>% mutate(Min_Time = Min_Function(c_across(starts_with("Min_") & -ends_with("0")), min))
Min_ID的实现方案
可以在现有rowwise()流程中,结合列名提取和位置匹配来生成Min_ID,同时保持动态筛选列的逻辑:
# 需提前加载stringr包用于提取数字,若不想加载可看下方替代方案 library(stringr) Data %>% rowwise() %>% mutate( # 临时存储每行的目标列数据与列名,避免重复筛选 target_data = list(c_across(starts_with("Min_") & -ends_with("0"))), Min_Time = Min_Function(unlist(target_data), min), Min_ID = ifelse(all(is.na(unlist(target_data))), NA, # 提取最小值对应列名的末尾数字 str_extract(names(unlist(target_data))[which.min(unlist(target_data))], "\\d+$") %>% as.integer()) ) %>% select(-target_data) # 移除临时辅助列
无stringr包的替代写法
如果不想依赖stringr,可以用基础R的sub函数提取列名数字:
Data %>% rowwise() %>% mutate( target_data = list(c_across(starts_with("Min_") & -ends_with("0"))), Min_Time = Min_Function(unlist(target_data), min), Min_ID = ifelse(all(is.na(unlist(target_data))), NA, sub("Min_", "", names(unlist(target_data))[which.min(unlist(target_data))]) %>% as.integer()) ) %>% select(-target_data)
逻辑说明
- 用
list()存储每行的目标列数据,避免重复调用c_across提升效率; which.min()定位最小值所在的位置,结合names()获取对应列名;- 通过字符串处理提取列名末尾的数字,转为整数类型;
- 用
ifelse处理全NA的行,返回NA值匹配需求。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

