Вы можете или не можете хотеть +1
в том, что вы называете delta
, зависит от того, включает ли ваш X
столбец «константы» (т.е. все значения = 1)
В противном случае это выглядит нормально, если немного не пифоново. Я хотел бы написать их больше как:
import numpy as np
from numpy.linalg import inv
from scipy.linalg import sqrtm
def solve_theta(X, Y):
return np.linalg.solve(X.T @ X, X.T @ Y)
def ss_res(X, Y, theta):
res = Y - (X @ theta)
return np.sum(res ** 2)
def std_error(X, Y, theta):
nr, rank = X.shape
resid_df = nr - rank
residvar = ss_res(X, Y, theta) / resid_df
var_theta = residvar * inv(X.T @ X)
return np.diag(sqrtm(var_theta))[:,None]
Примечание: здесь используется оператор умножения матрицы в стиле Python 3.5 @
вместо записи .dot()
Числовая стабильность такого алгоритма не удивительна, вы можете посмотреть на использование SVD или QR-разложений. есть доступное описание того, как бы вы сделали это с SVD:
Джон Мандель (1982) «Использование разложения по сингулярным числам в регрессионном анализе» 10.1080 / 00031305.1982.10482771
Мы можем проверить это, создав несколько фиктивных данных:
np.random.seed(42)
N = 20
K = 3
true_theta = np.random.randn(K, 1) * 5
X = np.random.randn(N, K)
Y = np.random.randn(N, 1) + X @ true_theta
и запустите указанный выше код:
theta = solve_theta(X, Y)
sse = std_error(X, Y, theta)
print(np.column_stack((theta, sse)))
, что дает:
[[ 2.23556391 0.35678574]
[-0.40643163 0.24751913]
[ 3.14687637 0.26461827]]
Мы можем проверить это с помощью statsmodels
:
import statsmodels.api as sm
sm.OLS(Y, X).fit().summary()
, что дает:
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
x1 2.2356 0.358 6.243 0.000 1.480 2.991
x2 -0.4064 0.248 -1.641 0.119 -0.929 0.116
x3 3.1469 0.266 11.812 0.000 2.585 3.709
что довольно близко.