Заменить вложенный ifelse в data.table - PullRequest
1 голос
/ 27 апреля 2020

Я хочу создать в моем data.table столбец, который принимает первое не NA значение из набора заданных столбцов:

library(data.table)
o <- data.table(a1 = c(1, NA, NA, NA), 
                a2 = c(NA, 2, NA, NA), 
                a3 = c(NA, NA, 3, NA),
                default = 11:14)
res <- copy(o)
res[, nc := ifelse(!is.na(a1), 
                   a1, 
                   ifelse(!is.na(a2), 
                          a2, 
                          ifelse(!is.na(a3),
                                 a3, 
                                 default)))][]
#    a1 a2 a3 default nc
# 1:  1 NA NA      11  1
# 2: NA  2 NA      12  2
# 3: NA NA  3      13  3
# 4: NA NA NA      14 14

Поскольку это становится довольно утомительным с большим количеством столбцов, Я хотел заменить это чем-то вроде l oop. Я прочитал Сокращенный вложенный ifelse и, по крайней мере, мог получить позицию первого не NA столбца с помощью max.col:

(col_ind <- o[, max.col(!sapply(.SD, is.na), "first"), .SDcol = patterns("^a|^default")])
# [1] 1 2 3 4

Как теперь можно "отобразить" столбец положение в колонке? С подмножеством матриц я мог бы сделать что-то вроде o[cbind(1:NROW(o), col_ind)], но это не работает по понятным причинам? У кого-нибудь есть идеи, как решить эту проблему (нет необходимости придерживаться подхода max.col, если для этого есть решение idomati c data.table?

1 Ответ

3 голосов
/ 27 апреля 2020

Некоторые необработанные идеи:

1) Использование fcase(), (которое в настоящее время доступно в версии для разработки):

o[, nc := fcase(
      !is.na(a1), a1,
      !is.na(a2), a2,
      !is.na(a3), a3,
      rep(TRUE, nrow(o)), as.double(default)
)]

2) Использование apply():

o[, 
  nc := apply(.SD, 1L, function(x) x[!is.na(x)][1L]), 
  .SDcol = patterns("^a|^default")]

3) Использование melt():

o[, row := .I]
o[, nc := o[, melt(.SD, id.vars = "row"), .SDcol = patterns("^a|^default|^row")
            ][!is.na(value), value[1L], by = row]$V1]
o[, row := NULL]

4) Использование set() с вектором col_ind:

for (i in seq_len(nrow(o))) set(o, i, "nc", value = o[[col_ind[i]]][i])

5) Использование max.col() с матричной цифрой c индексирование:

o[, nc := {
    m <- as.matrix(.SD)
    m[cbind(seq.int(.N), max.col(!is.na(m), "first"))]
}]

6) Использование fcoalesce():

o[, names(o) := lapply(.SD, as.integer)][, 
    nc := fcoalesce(.SD)]
  • Кредит на 5 и 6 для chinsoon12.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...