Ответ 1
Я следую вашему коду, кроме той части, где вы строите sparse.val
. Есть незначительные ошибки в том, как вы назначаете столбцы. Не забудьте проверить правильность ответа, пытаясь оптимизировать:).
Во-первых, создание data.table
:
Поскольку вы говорите, что вы уже знаете тип столбцов, важно создать правильный тип спереди. Иначе, когда вы делаете: DT[, LHS := RHS]
и RHS
тип не равен LHS
, RHS будет принуждаться к типу LHS. В вашем случае все ваши числовые и символьные значения будут преобразованы в логические, так как все столбцы являются логическими. Это не то, что вы хотите.
Таким образом, создание матрицы не поможет (все столбцы будут одного типа) + он также медленный. Вместо этого я бы сделал это следующим образом:
rows = 100L
cols = 1200L
outdf <- setDT(lapply(seq_along(cols), function(i) {
if (i < 401L) rep(NA, rows)
else if (i >= 402L & i < 801L) rep(NA_real_, rows)
else rep(NA_character_, rows)
}))
Теперь у нас есть правильный набор типов. Затем я думаю, что это должно быть i >= 402L & i < 801L
. В противном случае вы назначаете первые 401 столбцы как логические, а затем первые 801 столбцы как числовые, что, учитывая, что вы знаете тип столбцов вверх, не имеет большого смысла, правильно?
Во-вторых, сделав names(.) <-
:
Строка:
names(sparse.val) <- paste0("A", sparse.cols)
создаст копию и на самом деле не понадобится. Поэтому мы удалим эту строку.
В-третьих, время для цикла:
for(x in names(sparse.val)) {
val=sparse.val[[x]]
outdf[i, x:=val]
}
на самом деле не делает то, что, по вашему мнению, делает. Он не присваивает значения из val
имени, присвоенному x
. Вместо этого он записывает (каждый раз) в столбец с именем x
. Проверьте выходные данные.
Это не часть оптимизации. Это просто, чтобы вы знали, что вы на самом деле хотите сделать здесь.
for(x in names(sparse.val)) {
val=sparse.val[[x]]
outdf[i, (x) := val]
}
Обратите внимание на (
вокруг x
. Теперь он будет оценен, а значение, содержащееся в x
, будет столбцом, которому будет присвоено значение val
. Я понимаю немного тонко. Но это необходимо, потому что это позволяет создать столбец x
как DT[, x := val]
, где вы действительно хотите, чтобы val
был назначен x
.
Возвращаясь к оптимизации, хорошей новостью является то, что ваше трудоемкое for-loop просто:
set(outdf, i=i, j=paste0("A", sparse.cols), value = sparse.val)
Здесь используется data.table
вспомогательное назначение по ссылке!
Объединяя все это:
Ваша последняя функция выглядит следующим образом:
timeMe2 <- function() {
set.seed(1L)
rows = 100L
cols = 1200L
outdf <- as.data.table(lapply(seq_len(cols), function(i) {
if (i < 401L) rep(NA, rows)
else if (i >= 402L & i < 801L) rep(NA_real_, rows)
else sample(rep(NA_character_, rows))
}))
setnames(outdf, paste0("A", seq(1:1200)))
for(i in seq(100)) {
sparse.cols <- sample(1200L, 100L)
sparse.val <- lapply(sparse.cols, function(i) {
if(i < 401L) sample(c(TRUE, FALSE), 1)
else if (i >= 402 & i < 801L) sample(seq(10), 1)
else sample(LETTERS, 1)
})
set(outdf, i=i, j=paste0("A", sparse.cols), value = sparse.val)
}
outdf
}
Таким образом, ваше решение занимает 9,84 секунды в моей системе, тогда как вышеприведенная функция занимает 0,34 секунды, что составляет ~ 29 раз. Я думаю, что это результат, который вы ищете. Пожалуйста, проверьте его.
НТН