R按ID分组提取多变量各自最大值对应行的问题求解
问题描述
我有一个按ID分组的data.frame,每个ID对应多行数据,包含a、b、c等多个变量。
示例数据如下:
dt <- structure(list(ID = c(1, 1, 2, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10), a = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), b = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), c = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), d = c(1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1), e = c(0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1), f = c(1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1), g = c(1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1), h = c(1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1), i = c(1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1)), row.names = c(NA, -31L), class = c("tbl_df", "tbl", "data.frame"))
我需要针对每个ID,提取各变量对应的最大值(取第一个或最后一个最大值实例不影响需求)。目前仅针对单个变量提取分组最大值的教程较多,但我在多变量场景下复现逻辑时遇到了问题。
我使用data.table和lapply的尝试代码如下:
library(data.table) setDT(dt) variables = colnames(dt[, 2:10]) dt_max = dt[, lapply(.SD, which.max), .SDcols = variables, by = "ID"]
运行后返回的是最大值对应的行索引,而非各变量的最大值,不符合需求,运行结果如下:
ID a b c d e f g h i 1: 1 1 1 1 1 2 1 1 1 1 2: 2 1 1 1 1 1 1 1 1 1 3: 3 1 1 1 1 5 1 1 2 1 4: 4 1 1 1 1 1 1 1 1 1 5: 5 1 1 1 1 1 3 1 1 1 6: 6 1 1 1 1 1 1 1 1 1 7: 7 1 1 1 1 1 1 1 1 1 8: 8 1 1 1 1 1 2 1 2 2 9: 9 1 1 1 1 1 2 1 1 1 10: 10 1 1 1 1 1 1 1 1 1
我期望得到的输出如下:
ID a b c d e f g h i 1: 1 1 1 1 1 1 1 1 1 1 2: 2 1 1 1 0 0 1 1 0 1 3: 3 1 1 1 0 1 1 1 1 1 4: 4 1 1 1 0 0 1 1 0 0 5: 5 1 1 1 1 1 1 1 0 0 6: 6 1 1 1 1 1 1 1 0 1 7: 7 1 1 1 1 1 0 1 0 0 8: 8 1 1 1 1 0 1 1 1 1 9: 9 1 1 1 0 1 1 1 0 0 10: 10 1 1 1 1 1 1 1 1 1
解决方案
问题根源是which.max()返回的是分组内最大值对应的行下标,不是最大值本身,因此得到的结果都是索引值,和需求不符。
直接将which.max替换为max即可得到预期结果,修改后的代码如下:
library(data.table) setDT(dt) variables = colnames(dt[, 2:10]) dt_max = dt[, lapply(.SD, max), .SDcols = variables, by = "ID"]
该方案为data.table原生向量化运算,处理百万级以上数据时仍能保持很高的效率,不需要逐个变量处理再合并。
内容的提问来源于stack exchange,提问作者jmogil
相关产品推荐
相关产品推荐

