Из того, что я могу сказать, это завершается так же, как ваш код менее чем за полсекунды на моей машине:
library(data.table)
DT = as.data.table(matrix(rnorm(times * cols, mean = 5), times, cols))
setnames(DT, c('A', 'B', 'C', 'X'))
DT[ , grp := rep(seq_len(1e3), each = 100)]
setkey(DT, grp)
DT[DT[ , lapply(.SD, max), keyby = grp, .SDcols = !'X'
][ , X := Reduce(`+`, .SD)/ncol(.SD), .SDcols = !'grp'], {
i.A; i.B; i.C; i.X
lapply(names(.SD), function(j)
which.max(eval(as.name(j)) < .5 * eval(as.name(paste0('i.', j)))))
}, on = 'grp', by = .EACHI, .SDcols = !'grp']
# grp V1 V2 V3 V4
# 1: 1 3 30 1 4
# 2: 2 6 15 4 10
# 3: 3 2 5 7 2
# 4: 4 8 16 5 8
# 5: 5 10 3 1 7
# ---
# 996: 996 11 5 3 13
# 997: 997 3 3 3 11
# 998: 998 14 21 2 10
# 999: 999 18 2 1 41
# 1000: 1000 8 7 3 3
По сути, вы создаете справочную таблицу с соответствующими заглавными буквами и присоединяетесь обратно.
Вы можете отделить это, написав:
lookup =
DT[ , lapply(.SD, max), keyby = grp, .SDcols = !'X'
][ , X := Reduce(`+`, .SD)/ncol(.SD), .SDcols = !'grp']
DT[lookup, on = 'grp', {
i.A; i.B; i.C; i.X
lapply(names(.SD), function(j)
which.max(eval(as.name(j)) < .5 * eval(as.name(paste0('i.', j)))))
}, by = .EACHI, .SDcols = !'grp']
После того, как он отделен, вы также получаете гибкость получения get
(что, по моему опыту, медленнее, чем eval(as.name())
):
DT[lookup, on = 'grp', {
lapply(names(.SD), function(j)
which.max(eval(as.name(j)) < .5 * get(paste0('i.', j))))
}, by = .EACHI, .SDcols = !'grp']
# grp V1 V2 V3 V4
# 1: 1 1 5 26 3
# 2: 2 6 7 3 4
# 3: 3 2 6 1 13
# 4: 4 5 2 12 5
# 5: 5 9 12 2 4
# ---
# 996: 996 1 3 4 1
# 997: 997 1 6 3 13
# 998: 998 10 13 9 8
# 999: 999 2 4 13 4
# 1000: 1000 7 30 19 14