Почему model.matrix такой медленный?
Рассмотрим следующие демонстрационные данные:
set.seed(1)
n <- 1000000
x1 <- rnorm(n)
x2 <- rnorm(n)
x3 <- rnorm(n)
Если я построю матрицу mt
с model.matrix()
, это займет вечность:
system.time(mt <- model.matrix(~x1+x2+x3))
usuário sistema decorrido
0.916 0.185 1.135
Но если я сделаю то же самое с матрицей, это будет довольно быстро:
system.time(mt2 <- matrix(c(rep(1, n), x1, x2, x3), byrow=FALSE, ncol=4))
usuário sistema decorrido
0.085 0.021 0.105
Почему разница? Что делает model.matrix()
медленно действительно необходимо для lm()
и связанные функции?
2 ответа
С помощью debugonce(model.matrix.default)
и в рамках этого использования tracemem(data)
model.matrix.default
звонки model.frame
который возвращает data.frame
, В model.matrix.default
, этот data.frame копируется как минимум 3 раза.
Почему lm
использование model.matrix
-> lm
обычно вызывается с data.frame
, list
или же environment
как data
аргумент. model.frame
и возвращая data.frame
гарантирует, что термины в формуле могут быть найдены при последующих вызовах lm
и будет ссылаться на те же значения.
В общем, звонок в Rprof
(в library(utils)
который должен быть на search()
путь по умолчанию) проиллюстрирует, откуда возникают издержки во время вызова функции:
Rprof("Rprof.out")
m1 <- model.matrix( ~ x1 + x2 + x3)
Rprof(NULL)
summaryRprof("Rprof.out")
дающий
> summaryRprof("Rprof.out")
$by.self
self.time self.pct total.time total.pct
"model.matrix.default" 0.12 42.86 0.28 100.00
"na.omit.data.frame" 0.06 21.43 0.14 50.00
"[.data.frame" 0.04 14.29 0.08 28.57
"anyDuplicated.default" 0.04 14.29 0.04 14.29
"as.list.data.frame" 0.02 7.14 0.02 7.14
$by.total
total.time total.pct self.time self.pct
"model.matrix.default" 0.28 100.00 0.12 42.86
"model.matrix" 0.28 100.00 0.00 0.00
"na.omit.data.frame" 0.14 50.00 0.06 21.43
"model.frame" 0.14 50.00 0.00 0.00
"model.frame.default" 0.14 50.00 0.00 0.00
"na.omit" 0.14 50.00 0.00 0.00
"[.data.frame" 0.08 28.57 0.04 14.29
"[" 0.08 28.57 0.00 0.00
"anyDuplicated.default" 0.04 14.29 0.04 14.29
"anyDuplicated" 0.04 14.29 0.00 0.00
"as.list.data.frame" 0.02 7.14 0.02 7.14
"as.list" 0.02 7.14 0.00 0.00
"vapply" 0.02 7.14 0.00 0.00
$sample.interval
[1] 0.02
$sampling.time
[1] 0.28
Таким образом, большое количество времени тратится на проверку NA
с na.omit.data.frame
и подмножество data.frame
с [.data.frame
, в model.frame.default
, Пропорции времени будут варьироваться в зависимости от размера выборки. n
, но будет стремиться к пределу для больших размеров выборки.