Uwaga : opublikowałem rozszerzoną wersję tej odpowiedzi na mojej stronie internetowej .
Czy uprzejmie rozważysz opublikowanie podobnej odpowiedzi przy odsłoniętym silniku R?
Pewnie! W dół króliczej nory idziemy.
Pierwsza warstwa to lm
interfejs udostępniony programatorowi R. Możesz zajrzeć do źródła tego po prostu pisząc lm
na konsoli R. Większość z nich (podobnie jak większość kodu na poziomie produkcyjnym) zajmuje się sprawdzaniem danych wejściowych, ustawianiem atrybutów obiektu i zgłaszaniem błędów; ale ta linia wystaje
lm.fit(x, y, offset = offset, singular.ok = singular.ok,
...)
lm.fit
to kolejna funkcja R, którą możesz nazwać samodzielnie. Chociaż lm
wygodnie współpracuje z formułami i ramką danych, lm.fit
chce macierzy, więc usunięto jeden poziom abstrakcji. Sprawdzanie źródła lm.fit
, więcej pracy i następujący naprawdę interesujący wiersz
z <- .Call(C_Cdqrls, x, y, tol, FALSE)
Teraz gdzieś idziemy. .Call
jest sposobem wywoływania przez R. kodu C. Istnieje gdzieś funkcja C, C_Cdqrls w źródle R. I musimy ją znaleźć. Oto jest .
Patrząc na funkcję C, znowu znajdujemy głównie sprawdzanie granic, usuwanie błędów i zajęty pracę. Ale ta linia jest inna
F77_CALL(dqrls)(REAL(qr), &n, &p, REAL(y), &ny, &rtol,
REAL(coefficients), REAL(residuals), REAL(effects),
&rank, INTEGER(pivot), REAL(qraux), work);
Tak więc teraz jesteśmy w naszym trzecim języku, R nazywa C, który wzywa do fortranu. Oto kod fortran .
Pierwszy komentarz mówi wszystko
c dqrfit is a subroutine to compute least squares solutions
c to the system
c
c (1) x * b = y
(co ciekawe, wygląda na to, że nazwa tej procedury została w pewnym momencie zmieniona, ale ktoś zapomniał zaktualizować komentarz). W końcu jesteśmy w punkcie, w którym możemy wykonać algebrę liniową i rozwiązać układ równań. To jest coś, w czym fortran jest naprawdę dobry, co wyjaśnia, dlaczego przeszliśmy przez tak wiele warstw, aby się tu dostać.
Komentarz wyjaśnia również, co zrobi kod
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 rozwiąże system, znajdując rozkład .QR
Pierwszą rzeczą, która się zdarza, i zdecydowanie najważniejszą, jest
call dqrdc2(x,n,n,p,tol,k,qraux,jpvt,work)
To wywołuje funkcję fortran dqrdc2
na naszej macierzy wejściowej x
. Co to jest?
c dqrfit uses the linpack routines dqrdc and dqrsl.
W końcu dotarliśmy do Linpacka . Linpack jest fortranową biblioteką algebry liniowej, która istnieje od lat 70. Najpoważniejsza algebra liniowa ostatecznie trafia do linpack. W naszym przypadku korzystamy z funkcji dqrdc2
c dqrdc2 uses householder transformations to compute the qr
c factorization of an n by p matrix x.
Właśnie tam wykonywana jest praca. Zajmie mi to cały dzień, żeby dowiedzieć się, co robi ten kod. Jest tak niski, jak to tylko możliwe. Ale generalnie mamy macierz i chcemy ją uwzględnić w produkcie gdzie jest macierzą ortogonalną, a jest górną trójkątną macierzą. Jest to mądra rzecz do zrobienia, ponieważ gdy masz i , możesz rozwiązać równania liniowe dla regresjiXX=QRQRQR
XtXβ=XtY
bardzo łatwo. W rzeczy samej
XtX=RtQtQR=RtR
cały system staje się
RtRβ=RtQty
ale jest górnym trójkątem i ma taką samą rangę jakRXtX , więc dopóki nasz problem jest dobrze postawiony, ma pełną rangę i równie dobrze możemy po prostu rozwiązać zredukowany system
Rβ=Qty
Ale oto niesamowita rzecz. jest górnym trójkątem, więc ostatnie równanie liniowe jest tutaj , więc rozwiązywanie β n jest banalne. Następnie możesz wchodzić po rzędach, jeden po drugim, i zamieniać β, które już znasz, za każdym razem uzyskując proste równanie liniowe o zmiennej zmiennej do rozwiązania. Tak więc, kiedy masz Q i R , cała sprawa zapada się do tak zwanej substytucji wstecznej , co jest łatwe. Możesz przeczytać o tym bardziej szczegółowo tutaj , gdzie w pełni opracowano wyraźny mały przykład.Rconstant * beta_n = constant
βnβQR