Примечание . Я разместил расширенную версию этого ответа на своем веб-сайте .
Не могли бы вы опубликовать аналогичный ответ с действительным 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-код. Где-то есть функция C, C_Cdqrls в источнике R, и нам нужно ее найти. Здесь .
Глядя на функцию 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.
Итак, Фортран собирается решить систему, найдя разложение Q R
Первое, что происходит, и, безусловно, самое важное, это
call dqrdc2(x,n,n,p,tol,k,qraux,jpvt,work)
Это вызывает функцию fortran dqrdc2
в нашей входной матрице x
. Что это?
c dqrfit uses the linpack routines dqrdc and dqrsl.
Итак, мы наконец-то добрались до linpack . Linpack - это библиотека линейной алгебры Фортрана, которая существует с 70-х годов. Наиболее серьезная линейная алгебра в конечном итоге находит свой путь в linpack. В нашем случае мы используем функцию 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, вы можете решить линейные уравнения для регрессии.ИксИкс= Q RQрQр
ИксTИксβ= XTY
очень легко. Верно
ИксTИкс= RTQTQ R = RTр
так что вся система становится
рTR β= RTQTY
но имеет верхнюю треугольную форму и имеет тот же ранг, что и X t X , поэтому, пока наша задача хорошо поставлена, она является полным рангом, и мы можем также просто решить приведенную системурИксTИкс
R β= QTY
Но вот потрясающая вещь. верхняя треугольная, поэтому последнее линейное уравнение здесь просто , поэтому решение для β n тривиально. Затем вы можете пройти вверх по строкам, одну за другой, и подставить в β, которые вы уже знаете, каждый раз, получая простое линейное уравнение с одной переменной для решения. Итак, когда у вас есть Q и R , все это сводится к тому, что называется обратной заменой , что легко. Вы можете прочитать об этом более подробно здесь , где явный маленький пример полностью проработан.рconstant * beta_n = constant
βNβQр