Hinweis : Ich habe eine erweiterte Version dieser Antwort auf meiner Website veröffentlicht .
Würden Sie freundlicherweise in Betracht ziehen, eine ähnliche Antwort mit dem tatsächlichen R-Motor zu veröffentlichen?
Sicher! Das Kaninchenloch runter gehen wir.
Die erste Schicht ist lm
die Schnittstelle, die dem R-Programmierer ausgesetzt ist. Sie können die Quelle dafür anzeigen, indem Sie einfach lm
an der R-Konsole tippen. Der größte Teil davon (wie der größte Teil des Codes auf Produktionsebene) ist damit beschäftigt, Eingaben zu überprüfen, Objektattribute festzulegen und Fehler zu werfen. aber diese Linie ragt heraus
lm.fit(x, y, offset = offset, singular.ok = singular.ok,
...)
lm.fit
ist eine andere R-Funktion, die Sie selbst aufrufen können. Funktioniert zwar lm
bequem mit Formeln und Datenrahmen, lm.fit
möchte aber Matrizen, so dass eine Abstraktionsebene entfernt wird. lm.fit
Suchen Sie nach der Quelle , nach mehr Arbeit und nach der folgenden wirklich interessanten Zeile
z <- .Call(C_Cdqrls, x, y, tol, FALSE)
Jetzt kommen wir voran. .Call
ist Rs Art, C-Code aufzurufen. Es gibt eine C-Funktion, C_Cdqrls, irgendwo in der R-Quelle, und wir müssen sie finden. Hier ist es .
Wenn wir uns die C-Funktion noch einmal ansehen, finden wir meistens eine Überprüfung der Grenzen, eine Fehlerbereinigung und viel Arbeit. Aber diese Linie ist anders
F77_CALL(dqrls)(REAL(qr), &n, &p, REAL(y), &ny, &rtol,
REAL(coefficients), REAL(residuals), REAL(effects),
&rank, INTEGER(pivot), REAL(qraux), work);
Jetzt sind wir in unserer dritten Sprache, R hat C gerufen, was fortran anruft. Hier ist der Fortran-Code .
Der erste Kommentar sagt alles
c dqrfit is a subroutine to compute least squares solutions
c to the system
c
c (1) x * b = y
(Interessanterweise wurde der Name dieser Routine irgendwann geändert, aber jemand hat vergessen, den Kommentar zu aktualisieren). Damit sind wir endlich an dem Punkt angelangt, an dem wir eine lineare Algebra erstellen und das Gleichungssystem tatsächlich lösen können. Dies ist die Art von Dingen, in denen Fortran wirklich gut ist, was erklärt, warum wir so viele Schichten durchlaufen haben, um hierher zu gelangen.
Der Kommentar erklärt auch, was der Code tun wird
c on return
c
c x contains the output array from dqrdc2.
c namely the qr decomposition of x stored in
c compact form.
Also wird fortran das System lösen, indem es die Zerlegung findet.Q R
Das Erste, was passiert, und bei weitem das Wichtigste, ist
call dqrdc2(x,n,n,p,tol,k,qraux,jpvt,work)
Dies ruft die fortran -Funktion dqrdc2
in unserer Eingabematrix auf x
. Was ist das?
c dqrfit uses the linpack routines dqrdc and dqrsl.
Also haben wir es endlich geschafft, Linpack zu machen . Linpack ist eine Fortran-Bibliothek für lineare Algebra, die es seit den 70er Jahren gibt. Die schwerste lineare Algebra findet schließlich ihren Weg zum Linpack. In unserem Fall verwenden wir die Funktion dqrdc2
c dqrdc2 uses householder transformations to compute the qr
c factorization of an n by p matrix x.
Hier wird die eigentliche Arbeit erledigt. Es würde einen guten ganzen Tag dauern, bis ich herausgefunden hätte, was dieser Code tut. Er ist so niedrig wie er kommt. Aber im Allgemeinen haben wir eine Matrix und wollen sie in ein Produkt zerlegen, wobei eine orthogonale Matrix und eine obere Dreiecksmatrix ist. Dies ist eine kluge Sache, denn sobald Sie und , können Sie die linearen Gleichungen für die Regression lösenX = Q R Q R Q RXX= Q RQ.RQ.R
XtXβ= XtY.
sehr leicht. Tatsächlich
XtX= RtQ.tQ R = RtR
so wird das ganze system
RtR β= RtQ.ty
aber ist das obere Dreieck und hat den gleichen Rang wie , solange unser Problem gut gestellt ist, ist es der volle Rang, und wir können das reduzierte System genauso gut lösenX t XRXtX
R β= Qty
Aber hier ist die tolle Sache. ist das obere Dreieck, also ist die letzte lineare Gleichung gerade , also ist das Auflösen nach trivial. Sie können dann die Zeilen nacheinander durchlaufen und die bereits bekannten Werte ersetzen , wobei Sie jedes Mal eine einfache lineare Gleichung mit einer Variablen zur Lösung erhalten. Sobald Sie also und , kollabiert das Ganze zu einer so genannten Rückwärtssubstitution , was einfach ist. Sie können hier ausführlicher darüber lesen , wo ein explizites kleines Beispiel vollständig ausgearbeitet ist.β n β Q RRconstant * beta_n = constant
βnβQ.R