Добавить несколько столбцов с rep в data.table - PullRequest
0 голосов
/ 25 июня 2018

Я пытаюсь создать фиксированное количество столбцов (в данном случае 4 столбца) с помощью функции rep. В столбце B упоминается, как часто число 1 должно повторяться в этих столбцах. Остальные столбцы должны быть заполнены 0.

Но я получаю сообщение об ошибке

"Ошибка в rep (1, B): неверный аргумент 'times'"

и не знаю как это исправить

test <- data.table(A = c("XYZ", "ZYX", "WER"),
                   B = c(1, 3, 2))
cols <- LETTERS[3:6] 
test[, (cols) := c(rep(1, B), rep(0, length(cols) - B))]  

#result should be 
result <- data.table(A = c("XYZ", "ZYX", "WER"),
                     B = c(1, 3, 2),
                     C = c(1, 1, 1),
                     D = c(0, 1, 1),
                     E = c(0, 1, 0),
                     F = c(0, 0, 0))

1 Ответ

0 голосов
/ 25 июня 2018

Здесь используется немного логики, отличной от 'data.table', но она должна быть довольно быстрой:

test[, (cols) := {
  D <- diag(length(cols))
  D[lower.tri(D)] <- 1
  data.table(D[B,])
}]

#     A B C D E F
#1: XYZ 1 1 0 0 0
#2: ZYX 3 1 1 1 0
#3: WER 2 1 1 0 0

Она работает, потому что создает матрицу с заполненной диагональю и нижним треугольником, изатем использует test$B для подмножества строк этой матрицы.

В качестве альтернативы, вы можете перебрать последовательность длин столбцов, которые нужно назначить, и проверить, равно ли значение или меньше:

test[, (cols) := lapply(1:length(cols), function(x) as.numeric(x <= B))]

Некоторые сравнительные тайминги с добавлением 24 столбцов и 3M строк:

cols <- LETTERS[-(1:2)]
test <- test[rep(1:3,1e6),]

system.time(test[, (cols) := {
  D <- diag(length(cols))
  D[lower.tri(D)] <- 1
  data.table(D[B,])
}])

#   user  system elapsed 
#  0.937   0.651   1.591 

Побежден моим вторым усилием:

system.time(
  test[, (cols) := lapply(1:length(cols), function(x) as.numeric(x <= B))]
)
#   user  system elapsed 
#  0.313   0.132   0.446 
...