Представляет ли следующий код предпочтительную процедуру обхода строк R data.table
и передачи значений, найденных в каждой строке, в функцию? Или есть более производительный способ сделать это?
library(data.table)
set.seed(2)
n <- 100
b <- c(0.5, 1.5, -1)
phi <- 0.8
X <- cbind(1, matrix(rnorm(n*2, 0, 1), ncol = 2))
y <- X %*% matrix(b, ncol = 1) + rnorm(n, 0, phi)
d <- data.table(y, X)
setnames(d, c("y", "x0", "x1", "x2"))
logpost <- function(d, b1, b2, b3, phi, mub = 1, taub = 10, a = 0.5, z = 0.7){
N <- nrow(d)
mu <- b1 + b2 * d$x1 + b3 * d$x2
lp <- -N * log(phi) -
(1/(2*phi^2)) * sum( (d$y-mu)^2 ) -
(1/(2*taub^2))*( (b1-mub)^2 + (b2-mub)^2 + (b3-mub)^2 ) -
(a+1)*log(phi) - (z/phi)
lp
}
nn <- 21
grid <- data.table(
expand.grid(b1 = seq(0, 1, len = nn),
b2 = seq(1, 2, len = nn),
b3 = seq(-1.5, -0.5, len = nn),
phi = seq(0.4, 1.2, len = nn)))
grid[, id := 1:.N]
setkey(grid, id)
wraplogpost <- function(dd){
logpost(d, dd$b1, dd$b2, dd$b3, dd$phi)
}
start <- Sys.time()
grid[, lp := wraplogpost(.SD), by = seq_len(nrow(grid))]
difftime(Sys.time(), start)
# Time difference of 2.081544 secs
Изменить: отображать первые несколько записей
> head(grid)
b1 b2 b3 phi id lp
1: 0.00 1 -1.5 0.4 1 -398.7618
2: 0.05 1 -1.5 0.4 2 -380.3674
3: 0.10 1 -1.5 0.4 3 -363.5356
4: 0.15 1 -1.5 0.4 4 -348.2663
5: 0.20 1 -1.5 0.4 5 -334.5595
6: 0.25 1 -1.5 0.4 6 -322.4152
Я пытался использовать set
, но этот подход кажется хуже
start <- Sys.time()
grid[, lp := NA_real_]
for(i in 1:nrow(grid)){
llpp <- wraplogpost(grid[i])
set(grid, i, "lp", llpp)
}
difftime(Sys.time(), start)
# Time difference of 21.71291 secs
Изменить: отображать первые несколько записей
> head(grid)
b1 b2 b3 phi id lp
1: 0.00 1 -1.5 0.4 1 -398.7618
2: 0.05 1 -1.5 0.4 2 -380.3674
3: 0.10 1 -1.5 0.4 3 -363.5356
4: 0.15 1 -1.5 0.4 4 -348.2663
5: 0.20 1 -1.5 0.4 5 -334.5595
6: 0.25 1 -1.5 0.4 6 -322.4152
Предложения или указатели на соответствующие документы будут оценены.
Изменить: за комментарии:
start <- Sys.time()
grid[, lp := wraplogpost(.SD), by = .I]
difftime(Sys.time(), start)
Warning messages:
1: In b2 * d$x1 :
longer object length is not a multiple of shorter object length
2: In b3 * d$x2 :
longer object length is not a multiple of shorter object length
3: In d$y - mu :
longer object length is not a multiple of shorter object length
> difftime(Sys.time(), start)
Time difference of 0.01199317 secs
>
> head(grid)
b1 b2 b3 phi id lp
1: 0.00 1 -1.5 0.4 1 -620977.2
2: 0.05 1 -1.5 0.4 2 -620977.2
3: 0.10 1 -1.5 0.4 3 -620977.2
4: 0.15 1 -1.5 0.4 4 -620977.2
5: 0.20 1 -1.5 0.4 5 -620977.2
6: 0.25 1 -1.5 0.4 6 -620977.2
который генерирует неправильные значения для lp
.
Изменить спасибо за комментарии и ответы. Я знаю, что этот сценарий можно решить с помощью альтернативных методов, меня интересует, какой предпочтительный способ сделать это при использовании data.table
.
Изменить еще раз спасибо за ответы. Поскольку никто не задавался вопросом, как сделать это явно с помощью data.table
, на данный момент я предполагаю, что нет идеального способа добиться этого, не обращаясь к базе R.
by = .I
. Это быстрее, см.?.I
. - person Rui Barradas   schedule 18.04.2021.I
следует использовать для получения индексов строк вj
, а не в качестве терминаby
. Также ответ здесь: stackoverflow.com/a/37668187/2319695 предполагает (по крайней мере, для меня), что.I
не должен использоваться в предложении by. Я неправильно интерпретирую этот ответ? - person t-student   schedule 18.04.2021.I
возвращаетseq_len(nrow(grid))
, но быстрее, поскольку это значение вычисляется data.table. Попытайся. - person Rui Barradas   schedule 18.04.2021$
извлечений. Ваш цикл работал бы лучше, если бы ваши данные были матрицей, а не списком (т.е.data.table
). - person Cole   schedule 20.04.2021