Произведение списка столбцов в R data.table

#r #data.table

#r #data.table

Вопрос:

У меня есть большой список имен столбцов (переменных) R data.table, и я хочу создать столбец, содержащий произведение этих столбцов.

Пример:

 col_names <- c("season_1","season_2","season_3")
DT_example <- data.table(id=1:4,
                 season_1=c(1,1,0,0),
                 season_2=c(0,1,1,1),
                 season_3=c(1,0,1,0),
                 product=1)
  

data.table:

    id season_1 season_2 season_3 product
1:  1        1        0        1       1
2:  2        1        1        1       1
3:  3        0        1        1       1
4:  4        0        1        0       1
  

Решение, которое у меня есть, использует цикл «for», но это не очень эффективно:

 for(inc in col_names){
  nm1 <- as.symbol(inc)
  DT_example[,product:= product * eval(nm1)]
}
  

Результат:

    id season_1 season_2 season_3 product
1:  1        1        0        1       0
2:  2        1        1        0       0
3:  3        1        1        1       1
4:  4        0        1        0       0
  

Есть ли более быстрый способ сделать это, используя собственный синтаксис data.table?

Комментарии:

1. DT_example[, product := Reduce("*", .SD), .SDcols = col_names]

2. Показанные в примере данные и код для их воспроизведения не совпадают.

Ответ №1:

Вот четыре варианта. Первый, безусловно, самый эффективный, но предполагает, что мы имеем дело только с нулями и единицами.

 DT_example[, product := do.call(pmin, .SD), .SDcols = patterns("season")]

DT_example[, product := Reduce(`*`, .SD), .SDcols = patterns("season")]

DT_example[, product := apply(.SD, 1, prod), .SDcols = patterns("season")]

DT_example[, product := melt(.SD, id.vars = "id")[, prod(value), by = id]$V1]

# > DT_example
#    id season_1 season_2 season_3 product
# 1:  1        1        0        1       0
# 2:  2        1        1        1       1
# 3:  3        0        1        1       0
# 4:  4        0        1        0       0
  

Данные:

 DT_example <- data.table(
  id=1:4,
  season_1=c(1,1,0,0),
  season_2=c(0,1,1,1),
  season_3=c(1,1,1,0),
  product=1
)
  

Ответ №2:

Я думаю, вы могли бы использовать функции «применить» и «prod»:

 DT_example$product = apply(DT_example[,2:4], 1, prod)
  

Это применение функции «prod» (умножает каждый элемент того, что получает ir), к каждой строке (определяемой аргументом «1», поскольку «2» будет столбцом) «DT_example [,2: 4]».

Ответ №3:

Мы можем использовать prod сгруппированные по последовательности строк после выбора столбцов .SDcols . При prod na.rm необходимости также есть возможность удалить NA элементы.

 DT_example[,  Product := prod(.SD, na.rm = TRUE), by = 1:nrow(DT_example),
     .SDcols = patterns("season")]
  

-вывод

 DT_example
#   id season_1 season_2 season_3 product Product
#1:  1        1        0        1       1       0
#2:  2        1        1        1       1       1
#3:  3        0        1        1       1       0
#4:  4        0        1        0       1       0