R语言提取含字符串、NA及分组的dataframe最大/最小值对应行
R语言分组提取前n个极值行解决方案
需求说明
从包含字符串、NA缺失值以及分组字段的dataframe中,提取包含前n个最大/最小值的行:
- 同一行内的多个极值仅计为1个结果
- 每个分组最终刚好返回n行
用户此前尝试的写法未达到预期:
aggregate(. ~ Group, df, function(x) max(head(sort(x),2),na.rm=T))
示例说明
当n=2时,需要为每个分组提取包含top2最大值的行,样例数据结构如下:
V01_Code V01_Corr V01_Lag V02_Code V02_Corr V02_Lag V03_Code V03_Corr V03_Lag V04_Code V04_Corr V04_Lag Group 1 AMI 0.63 L7 <NA> NA <NA> <NA> NA <NA> <NA> NA <NA> B 2 CII -0.61 L7 CMI -0.53 L7 <NA> NA <NA> <NA> NA <NA> A 3 AFI 0.51 L7 <NA> NA <NA> <NA> NA <NA> <NA> NA <NA> A 4 AII 0.52 L7 BII 0.62 L4 BMI 0.60 L7 III 0.58 L4 B 5 BII 0.52 L7 IIA 0.74 L6 III 0.51 L7 IMA 0.75 L6 A 6 AII 0.58 L6/L7 BII 0.69 L4 BMI 0.70 L7 IIA 0.57 L4 A 7 IIA 0.58 L6 IMA 0.59 L6 IMI 0.52 L6 <NA> NA <NA> B 8 IMU 0.52 L6 <NA> NA <NA> <NA> NA <NA> <NA> NA <NA> A
预期输出为:
V01_Code V01_Corr V01_Lag V02_Code V02_Corr V02_Lag V03_Code V03_Corr V03_Lag V04_Code V04_Corr V04_Lag Group 5 BII 0.52 L7 IIA 0.74 L6 III 0.51 L7 IMA 0.75 L6 A 6 AII 0.58 L6/L7 BII 0.69 L4 BMI 0.70 L7 IIA 0.57 L4 A 1 AMI 0.63 L7 <NA> NA <NA> <NA> NA <NA> <NA> NA <NA> B 4 AII 0.52 L7 BII 0.62 L4 BMI 0.60 L7 III 0.58 L4 B
测试数据dput结构:
structure(list(V01_Code = c("AMI", "CII", "AFI", "AII", "BII", "AII", "IIA", "IMU"), V01_Corr = c(0.63, -0.61, 0.51, 0.52, 0.52, 0.58, 0.58, 0.52), V01_Lag = c("L7", "L7", "L7", "L7", "L7", "L6/L7", "L6", "L6"), V02_Code = c(NA, "CMI", NA, "BII", "IIA", "BII", "IMA", NA), V02_Corr = c(NA, -0.53, NA, 0.62, 0.74, 0.69, 0.59, NA), V02_Lag = c(NA, "L7", NA, "L4", "L6", "L4", "L6", NA), V03_Code = c(NA, NA, NA, "BMI", "III", "BMI", "IMI", NA), V03_Corr = c(NA, NA, NA, 0.6, 0.51, 0.7, 0.52, NA), V03_Lag = c(NA, NA, NA, "L7", "L7", "L7", "L6", NA), V04_Code = c(NA, NA, NA, "III", "IMA", "IIA", NA, NA), V04_Corr = c(NA, NA, NA, 0.58, 0.75, 0.57, NA, NA), V04_Lag = c(NA, NA, NA, "L4", "L6", "L4", NA, NA), Group = c("B", "A", "A", "B", "A", "A", "B", "A")), row.names = c("1", "2", "3", "4", "5", "6", "7", "8"), class = "data.frame")
实现代码
使用dplyr包的实现逻辑如下:先按分组计算每行所有数值列(后缀为Corr的列)的最大值作为该行的排序依据,按值排序后取前n行即可。
library(dplyr) # 导入测试数据 df <- structure(list(V01_Code = c("AMI", "CII", "AFI", "AII", "BII", "AII", "IIA", "IMU"), V01_Corr = c(0.63, -0.61, 0.51, 0.52, 0.52, 0.58, 0.58, 0.52), V01_Lag = c("L7", "L7", "L7", "L7", "L7", "L6/L7", "L6", "L6"), V02_Code = c(NA, "CMI", NA, "BII", "IIA", "BII", "IMA", NA), V02_Corr = c(NA, -0.53, NA, 0.62, 0.74, 0.69, 0.59, NA), V02_Lag = c(NA, "L7", NA, "L4", "L6", "L4", "L6", NA), V03_Code = c(NA, NA, NA, "BMI", "III", "BMI", "IMI", NA), V03_Corr = c(NA, NA, NA, 0.6, 0.51, 0.7, 0.52, NA), V03_Lag = c(NA, NA, NA, "L7", "L7", "L7", "L6", NA), V04_Code = c(NA, NA, NA, "III", "IMA", "IIA", NA, NA), V04_Corr = c(NA, NA, NA, 0.58, 0.75, 0.57, NA, NA), V04_Lag = c(NA, NA, NA, "L4", "L6", "L4", NA, NA), Group = c("B", "A", "A", "B", "A", "A", "B", "A")), row.names = c("1", "2", "3", "4", "5", "6", "7", "8"), class = "data.frame") # 定义要提取的top n行数 n <- 2 result <- df %>% group_by(Group) %>% # 计算每行所有Corr列的最大值,自动忽略NA mutate(row_rank_val = max(c_across(ends_with("Corr")), na.rm = TRUE)) %>% # 按排序值降序排列,提取最小值时改为arrange(row_rank_val, .by_group = TRUE) arrange(desc(row_rank_val), .by_group = TRUE) %>% # 取每个分组前n行 slice_head(n = n) %>% ungroup() %>% # 删除辅助计算的列 select(-row_rank_val)
运行上述代码得到的result与预期输出完全一致。
内容的提问来源于stack exchange,提问作者Kimster
相关产品推荐
相关产品推荐

