Estoy tratando de ejecutar una regresión inflada a cero para una variable de respuesta continua en R. Soy consciente de una implementación gamlss, pero realmente me gustaría probar este algoritmo de Dale McLerran que es conceptualmente un poco más sencillo. Desafortunadamente, el código está en SAS y no estoy seguro de cómo volver a escribirlo para algo como nlme.
El código es el siguiente:
proc nlmixed data=mydata;
parms b0_f=0 b1_f=0
b0_h=0 b1_h=0
log_theta=0;
eta_f = b0_f + b1_f*x1 ;
p_yEQ0 = 1 / (1 + exp(-eta_f));
eta_h = b0_h + b1_h*x1;
mu = exp(eta_h);
theta = exp(log_theta);
r = mu/theta;
if y=0 then
ll = log(p_yEQ0);
else
ll = log(1 - p_yEQ0)
- lgamma(theta) + (theta-1)*log(y) - theta*log(r) - y/r;
model y ~ general(ll);
predict (1 - p_yEQ0)*mu out=expect_zig;
predict r out=shape;
estimate "scale" theta;
run;
De: http://listserv.uga.edu/cgi-bin/wa?A2=ind0805A&L=sas-l&P=R20779
AÑADIR:
Nota: Aquí no hay efectos mixtos, solo fijos.
La ventaja de este ajuste es que (aunque los coeficientes son los mismos que si ajusta por separado una regresión logística a P (y = 0) y una regresión de error gamma con enlace de registro a E (y | y> 0)) puede estimar la función combinada E (y) que incluye los ceros. Uno puede predecir este valor en SAS (con un CI) usando la línea predict (1 - p_yEQ0)*mu
.
Además, uno puede escribir declaraciones de contraste personalizadas para probar la importancia de las variables predictoras en E (y). Por ejemplo, aquí hay otra versión del código SAS que he usado:
proc nlmixed data=TestZIG;
parms b0_f=0 b1_f=0 b2_f=0 b3_f=0
b0_h=0 b1_h=0 b2_h=0 b3_h=0
log_theta=0;
if gifts = 1 then x1=1; else x1 =0;
if gifts = 2 then x2=1; else x2 =0;
if gifts = 3 then x3=1; else x3 =0;
eta_f = b0_f + b1_f*x1 + b2_f*x2 + b3_f*x3;
p_yEQ0 = 1 / (1 + exp(-eta_f));
eta_h = b0_h + b1_h*x1 + b2_h*x2 + b3_h*x3;
mu = exp(eta_h);
theta = exp(log_theta);
r = mu/theta;
if amount=0 then
ll = log(p_yEQ0);
else
ll = log(1 - p_yEQ0)
- lgamma(theta) + (theta-1)*log(amount) - theta*log(r) - amount/r;
model amount ~ general(ll);
predict (1 - p_yEQ0)*mu out=expect_zig;
estimate "scale" theta;
run;
Luego, para estimar "gift1" versus "gift2" (b1 versus b2) podemos escribir esta declaración de estimación:
estimate "gift1 versus gift 2"
(1-(1 / (1 + exp(-b0_f -b1_f))))*(exp(b0_h + b1_h)) - (1-(1 / (1 + exp(-b0_f -b2_f))))*(exp(b0_h + b2_h)) ;
¿Puede R hacer esto?
Respuestas:
Después de pasar un tiempo en este código, me parece que básicamente:
1) Hace una regresión logística con el lado derecho
b0_f + b1_f*x1
yy > 0
como una variable objetivo,2) Para aquellas observaciones para las cuales y> 0, realiza una regresión con el lado derecho
b0_h + b1_h*x1
, una probabilidad Gamma ylink=log
,3) También estima el parámetro de forma de la distribución Gamma.
Maximiza la probabilidad de forma conjunta, lo cual es bueno, porque solo tiene que hacer una llamada a la función. Sin embargo, la probabilidad se separa de todos modos, por lo que no obtendrá estimaciones de parámetros mejoradas como resultado.
Aquí hay un código R que hace uso de la
glm
función para ahorrar esfuerzo de programación. Esto puede no ser lo que le gustaría, ya que oscurece el algoritmo en sí. El código ciertamente tampoco es tan limpio como podría / debería ser.El parámetro de forma para la distribución Gamma es igual a 1 / el parámetro de dispersión para la familia Gamma. Se puede acceder a los coeficientes y otras cosas a las que le gustaría acceder programáticamente en los elementos individuales de la lista de valores de retorno:
La predicción se puede hacer usando la salida de la rutina. Aquí hay más código R que muestra cómo generar los valores esperados y alguna otra información:
Y una muestra de ejecución:
Ahora para la extracción de coeficientes y los contrastes:
fuente
foo.pred$fit
da la estimación puntual de E (y), pero el componentefoo.pred$pred.ygt0$pred
le daría E (y | y> 0). Agregué el cálculo de error estándar para y, por cierto, devuelto como se.fit. Los coeficientes pueden obtenerse de los componentes mediante coeficientes (foo.pred$pred.ygt0
) y coeficientes (foo.pred$pred.p.ygt0
); Escribiré una rutina de extracción y una rutina de contraste dentro de poco.