Ответ 1
Ни один из ответов пока не указал на правильное направление.
Принятый ответ @idr вызывает путаницу между lm
и summary.lm
. lm
не вычисляет никакой диагностической статистики вообще; вместо этого summary.lm
делает. Поэтому он говорит о summary.lm
.
@Jake является фактом о числовой стабильности QR-факторизации и LU/Choleksy факторизации. Aravindakshan answer расширяет это, указав количество операций с плавающей запятой за обе операции (хотя, по его словам, он не учитывал затраты на вычисление матрицы cross продукт). Но, не путайте счета ФЛОП с расходами на память. Фактически оба метода имеют одинаковое использование памяти в LINPACK/LAPACK. В частности, его аргумент о том, что метод QR стоит больше ОЗУ для хранения коэффициента Q
, является фиктивным. Сжатое хранилище, как описано в lm(): Что такое qraux, возвращаемое QR-декомпозицией в LINPACK/LAPACK, разъясняет, как вычисляется и сохраняется QR-факторизация. Скорость выпуска QR v.s. Чол подробно описан в моем ответе: Почему встроенная функция lm настолько медленная в R?, и мой ответ на быстрее lm
предоставляет небольшую процедуру lm.chol
с использованием метода Choleksy, который в 3 раза быстрее QR-метода.
@Greg ответ/предложение для biglm
хорош, но он не отвечает на вопрос. Поскольку упоминается biglm
, я хотел бы указать, что QR-разложение отличается в lm
и biglm
. biglm
вычисляет отражение домовладельца, так что полученный фактор R
имеет положительные диагонали. Подробнее см. Cholesky с помощью QR-факторизации. Причина, по которой biglm
делает это, заключается в том, что результирующий R
будет таким же, как фактор Cholesky, см. QR-декомпозицию и разложение Холески в R для информации. Кроме biglm
, вы можете использовать mgcv
. Прочтите мой ответ: biglm
предсказывать не удается выделить вектор размера xx.x MB для более подробной информации.
После сводки, пришло время опубликовать мой ответ.
Чтобы соответствовать линейной модели, lm
будет
- генерирует модельный кадр;
- создает матрицу модели;
- вызов
lm.fit
для QR-факторизации; - возвращает результат QR-факторизации, а также модельный фрейм в
lmObject
.
Вы сказали, что ваш входной кадр данных с 5 столбцами стоит 2 ГБ для хранения. С 20 уровнями факторов результирующая модельная матрица имеет около 25 колонок, вмещающих 10 ГБ памяти. Теперь давайте посмотрим, как увеличивается использование памяти при вызове lm
.
- [глобальная среда] изначально у вас есть хранилище на 2 ГБ для фрейма данных;
- [
lm
envrionment], затем он копируется в модельный кадр, стоимость которого составляет 2 ГБ; - [
lm
environment], тогда создается модельная матрица стоимостью 10 ГБ; - [
lm.fit
окружающая среда] копия матрицы модели производится, затем перезаписывается QR-факторизацией, стоимостью 10 ГБ; - [
lm
environment] возвращается результатlm.fit
, стоимость которого составляет 10 ГБ; - [глобальная среда] результат
lm.fit
возвращается ещеlm
, стоимость которого составляет еще 10 ГБ; - [глобальная среда] модельный кадр возвращается
lm
, стоимостью 2 ГБ.
Таким образом, требуется в общей сложности 46 ГБ оперативной памяти, намного больше, чем у вашей доступной 22 ГБ ОЗУ.
Собственно, если lm.fit
можно "вставить" в lm
, мы сэкономим 20 ГБ. Но нет возможности включить функцию R в другую функцию R.
Может быть, мы можем взять небольшой пример, чтобы увидеть, что происходит вокруг lm.fit
:
X <- matrix(rnorm(30), 10, 3) # a `10 * 3` model matrix
y <- rnorm(10) ## response vector
tracemem(X)
# [1] "<0xa5e5ed0>"
qrfit <- lm.fit(X, y)
# tracemem[0xa5e5ed0 -> 0xa1fba88]: lm.fit
Таким образом, X
копируется при передаче в lm.fit
. Давайте посмотрим, что qrfit
имеет
str(qrfit)
#List of 8
# $ coefficients : Named num [1:3] 0.164 0.716 -0.912
# ..- attr(*, "names")= chr [1:3] "x1" "x2" "x3"
# $ residuals : num [1:10] 0.4 -0.251 0.8 -0.966 -0.186 ...
# $ effects : Named num [1:10] -1.172 0.169 1.421 -1.307 -0.432 ...
# ..- attr(*, "names")= chr [1:10] "x1" "x2" "x3" "" ...
# $ rank : int 3
# $ fitted.values: num [1:10] -0.466 -0.449 -0.262 -1.236 0.578 ...
# $ assign : NULL
# $ qr :List of 5
# ..$ qr : num [1:10, 1:3] -1.838 -0.23 0.204 -0.199 0.647 ...
# ..$ qraux: num [1:3] 1.13 1.12 1.4
# ..$ pivot: int [1:3] 1 2 3
# ..$ tol : num 1e-07
# ..$ rank : int 3
# ..- attr(*, "class")= chr "qr"
# $ df.residual : int 7
Заметим, что компактная QR-матрица qrfit$qr$qr
такая же, как модельная матрица X
. Он создается внутри lm.fit
, но при выходе из lm.fit
он копируется. Итак, в общей сложности у нас будет 3 "копии" X
:
- оригинальный в глобальной среде;
- тот, который скопирован в
lm.fit
, перезаписан QR-факторизацией; - тот, который возвращается
lm.fit
.
В вашем случае X
составляет 10 ГБ, поэтому затраты памяти, связанные только с lm.fit
, уже составляют 30 ГБ. Не говоря уже о других расходах, связанных с lm
.
С другой стороны, взглянем на
solve(crossprod(X), crossprod(X,y))
X
занимает 10 ГБ, но crossprod(X)
- это только матрица 25 * 25
, а crossprod(X,y)
- это вектор длиной 25. Они настолько малы по сравнению с X
, поэтому использование памяти не увеличивается вообще.
Возможно, вы обеспокоены тем, что локальная копия X
будет сделана при вызове crossprod
? Не за что! В отличие от lm.fit
, который выполняет чтение и запись в X
, crossprod
только читает X
, поэтому копия не производится. Мы можем проверить это с помощью нашей игрушечной матрицы X
:
tracemem(X)
crossprod(X)
Вы не увидите копировального сообщения!
Если вы хотите короткую сводку для всех выше, вот она:
- затраты памяти для
lm.fit(X, y)
(или даже.lm.fit(X, y)
) в три раза больше, чем дляsolve(crossprod(X), crossprod(X,y))
; - В зависимости от того, насколько крупнее матрица модели, чем модель, затраты памяти для
lm
в 3 ~ 6 раз больше, чем дляsolve(crossprod(X), crossprod(X,y))
. Нижняя граница 3 никогда не достигается, а верхняя граница 6 достигается, когда модельная матрица такая же, как и модельная. Это тот случай, когда нет факториальных переменных или "фактор-подобных" терминов, таких какbs()
иpoly()
и т.д.