Предположим, у меня есть data.table вот так:
testdt <- data.table(col1 = c(1, 2, 3), col2=c(1.1, 1.9, 3.1), col3=c(1, 2.2, 3))
testdt
A data.table: 3 × 3
col1 col2 col3
<dbl> <dbl> <dbl>
1 1.1 1.0
2 1.9 2.2
3 3.1 3.0
Я пытаюсь получить имена первых и вторых имен столбцов с наименьшим значением и разницу между их значениями.
Результат будет выглядеть следующим образом:
A data.table: 3 × 8
col1 col2 col3 min_col min_value second_col second_value diff
<dbl> <dbl> <dbl> <chr> <dbl> <chr> <dbl> <dbl>
1 1.1 1.0 col1 1 col2 1.1 0.1
2 1.9 2.2 col2 1.9 col1 2 0.1
3 3.1 3.0 col1 3 col2 3.1 0.1
Итак, я начал с получения минимального имени и значения столбца:
testdt[, min_col := colnames(.SD)[max.col(-.SD, ties.method = "first")], .SDcols=c("col1", "col2", "col3")]
testdt[, min_value := pmin(col1, col2, col3)]
Но я не знаю, есть ли какой-нибудь способ получить остальное, что мне нужно, то есть второе самое низкое имя столбца и значение.
С frankv:
library(data.table)
testdt[
, min2_col := colnames(.SD)[apply(.SD, 1, \(x) which(frankv(x, ties.method = "dense") == 2)[1])],
.SDcols=c("col1", "col2", "col3")
][
, min2_value := unique(apply(.SD, 1, \(x) x[frankv(x, ties.method = "dense") == 2])),
.SDcols=c("col1", "col2", "col3")
][
, diff := min2_value - min_value
][]
col1 col2 col3 min_col min_value min2_col min2_value diff
1: 1 1.1 1.0 col1 1.0 col2 1.1 0.1
2: 2 1.9 2.2 col2 1.9 col1 2.0 0.1
3: 3 3.1 3.0 col1 3.0 col2 3.1 0.1
Другой подход (не самый красивый, но выполняет свою работу)
# create q row_id
testdt[, id := .I]
# melt to long, order by id and value
dt.melt <- melt(testdt, id.vars = "id")[order(id, value), ]
# summarise by id
dt.melt <- dt.melt[, .(min_col = variable[1],
min_value = value[1],
second_col = variable[!value == value[1]][1],
second_val = value[!value == value[1]][1]),
by = .(id)]
# calcuate differences
dt.melt[, diff := second_val - min_value]
# merge
cbind(testdt, dt.melt[, -1])
# col1 col2 col3 id min_col min_value second_col second_val diff
# 1: 1 1.1 1.0 1 col1 1.0 col2 1.1 0.1
# 2: 2 1.9 2.2 2 col2 1.9 col1 2.0 0.1
# 3: 3 3.1 3.0 3 col1 3.0 col2 3.1 0.1
На самом деле это решение работает быстрее на очень большом наборе данных. Вместо этого я приму это.
Я начал с этого подхода, но он действительно казался немного «грязным». Тем не менее, спасибо за ответ!