Мне предоставлена большая таблица данных, и мне нужно установить для ячеек фиксированное значение (например, 0) на основе номера столбца и индекса, зависящего от номера строки.
В качестве примера мне дана таблица данных 'dt', полная единиц. Кроме того, у меня есть вектор-столбец, указывающий количество столбцов (в строке), которые должны оставаться неизменными, а остальные должны быть установлены на 0.
dt <- setnames(data.table(matrix(1,nrow=100, ncol=11)),as.character(c(0:10)))
set.seed(1)
index <- sample(c(0:11),100, replace=TRUE)
> dput(index)
c(3L, 4L, 6L, 10L, 2L, 10L, 11L, 7L, 7L, 0L, 2L, 2L, 8L, 4L,
9L, 5L, 8L, 11L, 4L, 9L, 11L, 2L, 7L, 1L, 3L, 4L, 0L, 4L, 10L,
4L, 5L, 7L, 5L, 2L, 9L, 8L, 9L, 1L, 8L, 4L, 9L, 7L, 9L, 6L, 6L,
9L, 0L, 5L, 8L, 8L, 5L, 10L, 5L, 2L, 0L, 1L, 3L, 6L, 7L, 4L,
10L, 3L, 5L, 3L, 7L, 3L, 5L, 9L, 1L, 10L, 4L, 10L, 4L, 4L, 5L,
10L, 10L, 4L, 9L, 11L, 5L, 8L, 4L, 3L, 9L, 2L, 8L, 1L, 2L, 1L,
2L, 0L, 7L, 10L, 9L, 9L, 5L, 4L, 9L, 7L)
Например, в первой строке первые три ячейки остаются без изменений, а остальные устанавливаются равными 0. Поскольку это большая таблица данных, я ищу эффективный способ сделать это.
Спасибо за комментарий. Я на самом деле сделал, но забыл скопировать это здесь;)
Чтобы избежать сложности, я применил обратный подход и сначала заменил все 1 на 0. Затем двойной цикл for изменяет количество столбцов, указанных в индексе, на 1 с:
library(data.table)
dt <- setnames(data.table(matrix(0,nrow=100, ncol=11)),as.character(c(0:10)))
index <- sample(c(0:11),100, replace=TRUE)
for(i in 1:length(index)) {
if (index[i] > 0) {
for(j in 1:index[i]) {
dt[i,j] <- 1
}
}
}
замените dt[i,j] <- 1
на set(dt, i, j, 1)
и должно быть довольно быстро, иначе будет ужасно медленно
Поскольку у вас есть dt
, полный 1, вы можете воссоздать все data.table
с помощью
library(data.table)
cols <- ncol(dt)
data.table(t(sapply(seq_len(nrow(dt)), function(i)
rep(c(1, 0), c(index[i], cols - index[i])))))
# V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11
# 1: 1 1 1 0 0 0 0 0 0 0 0
# 2: 1 1 1 1 0 0 0 0 0 0 0
# 3: 1 1 1 1 1 1 0 0 0 0 0
# 4: 1 1 1 1 1 1 1 1 1 1 0
# 5: 1 1 0 0 0 0 0 0 0 0 0
# 6: 1 1 1 1 1 1 1 1 1 1 0
# 7: 1 1 1 1 1 1 1 1 1 1 1
# 8: 1 1 1 1 1 1 1 0 0 0 0
# 9: 1 1 1 1 1 1 1 0 0 0 0
#10: 0 0 0 0 0 0 0 0 0 0 0
#....
сравните его с первыми 10 index
значениями
index[1:10]
# [1] 3 4 6 10 2 10 11 7 7 0
Разве не наоборот (0/1)?
Вариант с использованием пакета Matrix
:
library(Matrix)
mat <- as.matrix(dt)
mat * as.matrix(sparseMatrix(
i=rep(seq_along(index), index),
j=unlist(sapply(index, seq_len)),
x=1))
Или используя data.table::set
:
for (j in seq_along(names(dt)))
set(dt, which(j>index), j, 0)
На самом деле я принял решение с помощью data.table::set. Это оказалось самым быстрым из текущих предложений.
last_col <- names(dt)[ncol(dt)]
for (r in seq_len(nrow(dt))) {
zero_from <- max(index[r]-1L, 0L)
set(dt, i = r, j = as.character(zero_from:last_col), value = 0)
}
set.seed()
перед созданием случайных данных для воспроизводимости