Покрокова лінійна обчислення алгебри з регресією найменших квадратів


22

Як приворот до питання про лінійно-змішані моделі в R, і поділитися як орієнтир для початківців / проміжних прихильників статистики, я вирішив опублікувати як незалежний "Q & A-стиль" кроки, пов'язані з "ручним" обчисленням коефіцієнти та прогнозовані значення простої лінійної регресії.

Приклад - вбудований R набір даних, mtcarsі він буде встановлений як милі на галон, споживаний транспортним засобом, що діє як незалежна змінна, регресуючи над вагою автомобіля (безперервна змінна) та кількістю циліндрів як фактор з трьома рівнями (4, 6 або 8) без взаємодій.

EDIT: Якщо вас зацікавило це запитання, ви обов'язково знайдете детальну та задовільну відповідь у цьому дописі від Matthew Drury поза резюме .


Коли ви говорите "ручне обчислення", чого ви шукаєте? Досить просто показати ряд порівняно простих кроків для отримання оцінок параметрів тощо (через ортогоналізацію Грам-Шмідта, наприклад, або операторами SWEEP), але це не так, як R робить обчислення внутрішньо; він (і більшість інших пакетів статистики) використовує розкладання QR (обговорюється в ряді публікацій на сайті - пошук на QR-розкладі відображає ряд публікацій, декілька з яких ви можете отримати прямо значення)
Glen_b -Встановити Моніку

Так. Я вважаю, що це було дуже приємно звертається у відповідь MD, я, мабуть, повинен редагувати свій пост, можливо, підкреслюючи геометричний підхід за моєю відповіддю - простір стовпців, матриця проекцій ...
Антоні Пареллада,

Так! @Matthew Drury Ви хочете, щоб я стерв цей рядок в ОП або оновив посилання?
Антоні Пареллада

1
Не впевнений, чи є у вас посилання, але це тісно пов'язане, і я дуже люблю відповідь JM. stats.stackexchange.com/questions/1829/…
Хайтао Ду

Відповіді:


51

Примітка . Я розмістив розширену версію цієї відповіді на своєму веб-сайті .

Ви б ласкаво розглянути можливість розміщення подібної відповіді з фактичним R-двигуном?

Звичайно! Вниз по кролячій норі ми йдемо.

Перший шар - lmце інтерфейс, підданий дії програміста R. Ви можете подивитися джерело цього, просто набравши lmконсоль R. Більшість із них (як і більшість більшості кодів виробництва) займається перевіркою входів, встановленням атрибутів об'єкта та викидом помилок; але ця лінія просувається

lm.fit(x, y, offset = offset, singular.ok = singular.ok, 
                ...)

lm.fit- це ще одна функція R, її можна назвати самостійно. Хоча lmзручно працювати з формулами та фреймом даних, lm.fitпотрібні матриці, тому цей рівень абстракції видалений. Перевірка джерела на наявність lm.fitбільш зайнятої роботи та наступний дійсно цікавий рядок

z <- .Call(C_Cdqrls, x, y, tol, FALSE)

Зараз ми кудись дістаємось. .Call- спосіб R ввести код C. У джерелі R десь є функція C, C_Cdqrls, і нам потрібно її знайти. Ось воно .

Знову, дивлячись на функцію C, ми знову виявляємо межі перевірки меж, очищення помилок та напруженої роботи. Але ця лінія інша

F77_CALL(dqrls)(REAL(qr), &n, &p, REAL(y), &ny, &rtol,
        REAL(coefficients), REAL(residuals), REAL(effects),
        &rank, INTEGER(pivot), REAL(qraux), work);

Отож, зараз ми на своїй третій мові, R назвав C, який закликає фортран. Ось код fortran .

Перший коментар розповідає все це

c     dqrfit is a subroutine to compute least squares solutions
c     to the system
c
c     (1)               x * b = y

(що цікаво, схоже, що назва цього розпорядку в певний момент було змінено, але хтось забув оновити коментар). Таким чином, ми нарешті знаходимося в точці, коли ми можемо зробити лінійну алгебру і реально вирішити систему рівнянь. Це така річ, у якій справді хороший фортран, який пояснює, чому ми пройшли через стільки шарів, щоб потрапити сюди.

У коментарі також пояснюється, що збирається робити код

c     on return
c
c        x      contains the output array from dqrdc2.
c               namely the qr decomposition of x stored in
c               compact form.

Тож fortran збирається вирішити систему, знайшовши розклад .QR

Перше, що відбувається, і, безумовно, найважливіше, - це

call dqrdc2(x,n,n,p,tol,k,qraux,jpvt,work)

Це викликає функцію fortran dqrdc2на вхідній матриці x. Що це?

 c     dqrfit uses the linpack routines dqrdc and dqrsl.

Отже, ми нарешті домігся до того, щоб розмовити . Лінпак - це бібліотека лінійної алгебри фортрана, яка існує з 70-х років. Більшість серйозних лінійних алгебр в кінцевому підсумку знаходить свій шлях до виправлення. У нашому випадку ми використовуємо функцію dqrdc2

c     dqrdc2 uses householder transformations to compute the qr
c     factorization of an n by p matrix x.

Тут робиться фактична робота. Мені знадобився б повний повний день, щоб зрозуміти, що робить цей код, він настільки ж низький, як вони приходять. Але загалом у нас є матриця і ми хочемо її розподілити на добуток де - ортогональна матриця, а - верхня трикутна матриця. Це розумно зробити, тому що, маючи і ви можете вирішити лінійні рівняння для регресіїX = Q R Q R Q RХХ=QRQRQR

ХтХβ=ХтY

дуже легко. Справді

ХтХ=RтQтQR=RтR

так стає вся система

RтRβ=RтQту

але є верхнім трикутним і має той же ранг, що і , так що поки наша проблема добре поставлена, вона є повноцінною, і ми можемо просто вирішити скорочену системуX t XRХтХ

Rβ=Qту

Але ось дивовижна річ. верхній трикутний, тому останнє лінійне рівняння тут просто , тому рішення для тривіальне. Потім ви можете підняти рядки, по черзі, і підміняти в які ви вже знаєте, щоразу отримуючи просте одне змінне лінійне рівняння для вирішення. Отже, як тільки у вас є і , вся справа руйнується до того, що називається зворотною заміною , що легко. Ви можете прочитати про це більш докладно тут , де повністю розроблений явний невеликий приклад.β n β Q RRconstant * beta_n = constantβнβQR


4
Це був найсмішніший математичний / кодуючий короткий нарис, який можна собі уявити. Я майже нічого не знаю про кодування, але ваша "екскурсія" по кишках, здавалося б, невинної функції R була справді відкриваючою на очі. Відмінне написання! Так як «люб'язно» зробив трюк ... Чи не могли б ви люб'язно розглянути цей як відповідний виклик? :-)
Антоні Пареллада

6
+1 Я цього раніше не бачив, приємний підсумок. Просто додати трохи інформації на випадок, якщо @Antoni не знайомий з перетвореннями домогосподарств; це, по суті, лінійне перетворення, яке дозволяє зняти з нуля одну частину матриці R, яку ви намагаєтеся досягти, не мукуючи деталі, з якими ви вже мали справу (поки ви проходите її в правильному порядку), що робить її ідеальною для перетворення матриць у верхню трикутну форму (обертання Генна виконують аналогічну роботу і, можливо, їх легше візуалізувати, але трохи повільніше).
Створюючи

2
Метью (+1), я пропоную вам розпочати або закінчити свою публікацію посиланням на ваші набагато детальніші записи про madrury.github.io/jekyll/update/2016/07/20/lm-in-R.html .
амеба каже, що повернеться до Моніки

3
-1 для куріння та не спускання машинного коду.
S. Kolassa - Відновіть Моніку

3
(Вибачте, просто жартую ;-)
С. Коласа - Відновіть Моніку

8

Фактичні покрокові розрахунки в R прекрасно описані у відповіді Метью Дрірі в цій самій нитці. У цій відповіді я хочу ознайомитись із процесом доведення себе, що результати R на простому прикладі можна досягти, слідуючи лінійній алгебрі проекцій на простір стовпця та концепції перпендикулярних (крапкових добутків) помилок, проілюстрованих у різних постах , і це добре пояснив доктор Странг у " Лінійній алгебрі та її додатках" , і тут легко можна отримати доступ .

β

мpг=iнтеrcеpт(cул=4)+β1шеiггодт+D1iнтеrcеpт(cул=6)+D2iнтеrcеpт(cул=8)[]

D1D2Х

attach(mtcars)    
x1 <- wt

    x2 <- cyl; x2[x2==4] <- 1; x2[!x2==1] <-0

    x3 <- cyl; x3[x3==6] <- 1; x3[!x3==1] <-0

    x4 <- cyl; x4[x4==8] <- 1; x4[!x4==1] <-0

    X <- cbind(x1, x2, x3, x4)
    colnames(X) <-c('wt','4cyl', '6cyl', '8cyl')

head(X)
        wt 4cyl 6cyl 8cyl
[1,] 2.620    0    1    0
[2,] 2.875    0    1    0
[3,] 2.320    1    0    0
[4,] 3.215    0    1    0
[5,] 3.440    0    0    1
[6,] 3.460    0    1    0

[]lm

βПrоjМатriх=(ХТХ)-1ХТ[ПrоjМатriх][у]=[RегrСоеf'с](ХТХ)-1ХТу=β

X_tr_X_inv <- solve(t(X) %*% X)    
Proj_M <- X_tr_X_inv %*% t(X)
Proj_M %*% mpg

          [,1]
wt   -3.205613
4cyl 33.990794
6cyl 29.735212
8cyl 27.919934

Ідентичний: coef(lm(mpg ~ wt + as.factor(cyl)-1)).

НатМатriх=Х(ХТХ)-1ХТ

HAT <- X %*% X_tr_X_inv %*% t(X)

у^Х(ХТХ)-1ХТуy_hat <- HAT %*% mpg

cyl <- as.factor(cyl); OLS <- lm(mpg ~ wt + cyl); predict(OLS):

y_hat <- as.numeric(y_hat)
predicted <- as.numeric(predict(OLS))
all.equal(y_hat,predicted)
[1] TRUE

1
Взагалі, в числових обчисленнях я вважаю, що найкраще вирішити лінійне рівняння, а не обчислити зворотну матрицю. Отже, я вважаю beta = solve(t(X) %*% X, t(X) %*% y), що на практиці точніше, ніж solve(t(X) %*% X) %*% t(X) %*% y.
Метью Друрі

R не робить це так - він використовує розкладання QR. Якщо ви збираєтесь описати використаний алгоритм , на комп’ютері я сумніваюся, що хтось використовує той, який ви показуєте.
Відновіть Моніку - Г. Сімпсон,

Не за алгоритмом, просто намагаючись зрозуміти основи лінійної алгебри.
Антоні Пареллада

@AntoniParellada Навіть у такому випадку я все ще вважаю, що мислення з точки зору лінійних рівнянь є більш яскравим у багатьох ситуаціях.
Меттью Друрі

1
Враховуючи периферійне співвідношення цього потоку з цілями нашого сайту, хоч і бачимо цінність в ілюструванні використання Rважливих розрахунків, я хотів би запропонувати вам розглянути можливість перетворення його на внесок у наш блог.
whuber
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.