Myślę, że sprowadza się to do początkowych wartości użytych w glm.fit
stosunku do tego, family$initialize
co sprawia, że metoda się różni. O ile wiem, glm.fit
rozwiąż problem, tworząc rozkład QR z gdzie jest macierzą projektową, a to przekątna z pierwiastkami kwadratowymi wpisów, jak opisano tutaj . Oznacza to, że wykorzystuje metodę Newtona-Raphsona.X √W−−√XXW−−√
Odpowiedni $intialize
kod to:
if (NCOL(y) == 1) {
if (is.factor(y))
y <- y != levels(y)[1L]
n <- rep.int(1, nobs)
y[weights == 0] <- 0
if (any(y < 0 | y > 1))
stop("y values must be 0 <= y <= 1")
mustart <- (weights * y + 0.5)/(weights + 1)
m <- weights * y
if (any(abs(m - round(m)) > 0.001))
warning("non-integer #successes in a binomial glm!")
}
Oto uproszczona wersja, glm.fit
która pokazuje mój punkt widzenia
> #####
> # setup
> y <- matrix(c(1,0,0,0), ncol = 1)
> weights <- 1:nrow(y) * 1000
> nobs <- length(y)
> family <- binomial()
> X <- matrix(rep(1, nobs), ncol = 1) # design matrix used later
>
> # set mu start as with family$initialize
> if (NCOL(y) == 1) {
+ n <- rep.int(1, nobs)
+ y[weights == 0] <- 0
+ mustart <- (weights * y + 0.5)/(weights + 1)
+ m <- weights * y
+ if (any(abs(m - round(m)) > 0.001))
+ warning("non-integer #successes in a binomial glm!")
+ }
>
> mustart # starting value
[,1]
[1,] 0.9995004995
[2,] 0.0002498751
[3,] 0.0001666111
[4,] 0.0001249688
> (eta <- family$linkfun(mustart))
[,1]
[1,] 7.601402
[2,] -8.294300
[3,] -8.699681
[4,] -8.987322
>
> #####
> # Start loop to fit
> mu <- family$linkinv(eta)
> mu_eta <- family$mu.eta(eta)
> z <- drop(eta + (y - mu) / mu_eta)
> w <- drop(sqrt(weights * mu_eta^2 / family$variance(mu = mu)))
>
> # code is simpler here as (X^T W X) is a scalar
> X_w <- X * w
> (.coef <- drop(crossprod(X_w)^-1 * ((w * z) %*% X_w)))
[1] -5.098297
> (eta <- .coef * X)
[,1]
[1,] -5.098297
[2,] -5.098297
[3,] -5.098297
[4,] -5.098297
>
> # repeat a few times from "start loop to fit"
Możemy powtórzyć ostatnią część jeszcze dwa razy, aby zobaczyć, że metoda Newtona-Raphsona różni się:
> #####
> # Start loop to fit
> mu <- family$linkinv(eta)
> mu_eta <- family$mu.eta(eta)
> z <- drop(eta + (y - mu) / mu_eta)
> w <- drop(sqrt(weights * mu_eta^2 / family$variance(mu = mu)))
>
> # code is simpler here as (X^T W X) is a scalar
> X_w <- X * w
> (.coef <- drop(crossprod(X_w)^-1 * ((w * z) %*% X_w)))
[1] 10.47049
> (eta <- .coef * X)
[,1]
[1,] 10.47049
[2,] 10.47049
[3,] 10.47049
[4,] 10.47049
>
>
> #####
> # Start loop to fit
> mu <- family$linkinv(eta)
> mu_eta <- family$mu.eta(eta)
> z <- drop(eta + (y - mu) / mu_eta)
> w <- drop(sqrt(weights * mu_eta^2 / family$variance(mu = mu)))
>
> # code is simpler here as (X^T W X) is a scalar
> X_w <- X * w
> (.coef <- drop(crossprod(X_w)^-1 * ((w * z) %*% X_w)))
[1] -31723.76
> (eta <- .coef * X)
[,1]
[1,] -31723.76
[2,] -31723.76
[3,] -31723.76
[4,] -31723.76
Nie dzieje się tak, jeśli zaczniesz od weights <- 1:nrow(y)
lub powiesz weights <- 1:nrow(y) * 100
.
Zauważ, że można uniknąć rozbieżności, ustawiając mustart
argument. Np
> glm(Y ~ 1,weights = w * 1000, family = binomial, mustart = rep(0.5, 4))
Call: glm(formula = Y ~ 1, family = binomial, weights = w * 1000, mustart = rep(0.5,
4))
Coefficients:
(Intercept)
-2.197
Degrees of Freedom: 3 Total (i.e. Null); 3 Residual
Null Deviance: 6502
Residual Deviance: 6502 AIC: 6504
weights
argument kończy się w dwóch miejscach wewnątrzglm.fit
funkcji (w glm.R ), czyli co działa w R: 1)binomial_dev_resids
w resztkach odchylenia, za pomocą funkcji C (w rodzinie. C ) i 2) w kroku IWLS za pomocąCdqrls
(w lm.c ). Nie znam wystarczającej ilości C, aby pomóc w śledzeniu logiki