Remarque : J'ai publié une version étendue de cette réponse sur mon site Web .
Envisageriez-vous de poster une réponse similaire avec le moteur R réel exposé?
Sûr! Dans le terrier du lapin, nous allons.
La première couche est lm
, l'interface exposée au programmeur R. Vous pouvez regarder la source pour cela en tapant simplement lm
sur la console R. La majorité (comme la majorité de la plupart des codes de niveau de production) est occupée à vérifier les entrées, à définir les attributs des objets et à lancer des erreurs; mais cette ligne ressort
lm.fit(x, y, offset = offset, singular.ok = singular.ok,
...)
lm.fit
est une autre fonction R, vous pouvez l'appeler vous-même. Bien qu'il lm
fonctionne de manière pratique avec des formules et un bloc de données, il lm.fit
souhaite des matrices, c'est donc un niveau d'abstraction supprimé. Vérification de la source lm.fit
, travail plus chargé et ligne vraiment intéressante suivante
z <- .Call(C_Cdqrls, x, y, tol, FALSE)
Nous arrivons maintenant quelque part. .Call
est la façon dont R appelle le code C. Il y a une fonction C, C_Cdqrls quelque part dans la source R, et nous devons la trouver. Ça y est .
En regardant la fonction C, encore une fois, nous trouvons principalement la vérification des limites, le nettoyage des erreurs et le travail occupé. Mais cette ligne est différente
F77_CALL(dqrls)(REAL(qr), &n, &p, REAL(y), &ny, &rtol,
REAL(coefficients), REAL(residuals), REAL(effects),
&rank, INTEGER(pivot), REAL(qraux), work);
Alors maintenant, nous en sommes à notre troisième langage, R a appelé C qui appelle fortran. Voici le code fortran .
Le premier commentaire dit tout
c dqrfit is a subroutine to compute least squares solutions
c to the system
c
c (1) x * b = y
(Fait intéressant, le nom de cette routine a changé à un moment donné, mais quelqu'un a oublié de mettre à jour le commentaire). Donc, nous sommes enfin au point où nous pouvons faire de l'algèbre linéaire et résoudre le système d'équations. C'est le genre de choses pour lesquelles fortran est vraiment bon, ce qui explique pourquoi nous avons traversé tant de couches pour arriver ici.
Le commentaire explique également ce que le code va faire
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 va donc résoudre le système en trouvant la décomposition QR
La première chose qui se produit, et de loin la plus importante, est
call dqrdc2(x,n,n,p,tol,k,qraux,jpvt,work)
Cela appelle la fonction fortran dqrdc2
sur notre matrice d'entrée x
. Qu'est-ce que c'est ça?
c dqrfit uses the linpack routines dqrdc and dqrsl.
Nous l'avons donc finalement fait pour linpack . Linpack est une bibliothèque d'algèbre linéaire fortran qui existe depuis les années 70. La plus sérieuse des algèbres linéaires trouve finalement son chemin vers linpack. Dans notre cas, nous utilisons la fonction dqrdc2
c dqrdc2 uses householder transformations to compute the qr
c factorization of an n by p matrix x.
C'est là que le travail réel est effectué. Il me faudrait une bonne journée complète pour comprendre ce que fait ce code, il est aussi bas que possible. Mais génériquement, nous avons une matrice et nous voulons la factoriser en un produit X = Q R où Q est une matrice orthogonale et R est une matrice triangulaire supérieure. C'est une chose intelligente à faire, car une fois que vous avez Q et R, vous pouvez résoudre les équations linéaires de régressionXX= Q RQRQR
XtXβ=XtY
très facilement. Effectivement
XtX=RtQtQR=RtR
de sorte que l'ensemble du système devient
RtRβ=RtQty
mais est triangulaire supérieur et a le même rang que X t X , donc tant que notre problème est bien posé, il est de rang complet, et nous pouvons tout aussi bien résoudre le système réduitRXtX
Rβ=Qty
Mais voici la chose impressionnante. est triangulaire supérieur, donc la dernière équation linéaire ici est juste , donc la résolution de β n est triviale. Vous pouvez ensuite remonter les lignes, une par une, et les remplacer par les β que vous connaissez déjà, en obtenant à chaque fois une équation linéaire simple à résoudre. Donc, une fois que vous avez Q et R , le tout s'effondre vers ce qu'on appelle la substitution à l'envers , ce qui est facile. Vous pouvez en savoir plus à ce sujet ici , où un petit exemple explicite est entièrement élaboré.Rconstant * beta_n = constant
βnβQR