Capítulo 6 Regresión logistica binaria

Otro modelo de predicción de aprendizaje supervisado es el de regresión logística. Se trata de un tipo de análisis de regresión utilizado para predecir el resultado de una variable categórica (aquella que puede adoptar un número limitado de categorías) en función de las variables predictoras. Este modelo se enmarca dentro de los modelos denominados de predicción lineal generalizados o glm como son conocidos por sus siglas en inglés.

Con el adjetivo binario nos referimos a las predicciones sobre variables binarias o dicotómicas que simplemente tratan de decir si algo es 1 o 0, SI o NO.

Este modelo de pronóstico se usa mucho en variables que se distribuyen en forma de binomial. La binomial es una distribución de probabilidad discreta que cuenta el número de éxitos en una secuencia de n ensayos. Si el evento de éxito tiene una probabilidad de ocurrencia p, la probabilidad del evento contrario -el de fracaso- tendrá una probabilidad de \(q = 1 - p\). En la distribución binomial se repite el experimento de éxito -fracaso n veces, de forma independiente, y se trata de calcular la probabilidad de un determinado número de éxitos d, en esas n repeticiones \(B(n,p)\).

La denominación de logística se debe precisamente a la forma de la propia función de distribución de probabilidad binomial que presenta un crecimiento exponencial y que se parece a una \(S\) y que toma el nombre matemático de función logística \(\frac{1}{1+e^{-t}}\).

Esta curva, es una aproximación continua a la función discreta binaria, pues el cambio de 0 a 1 se produce en corto espacio y muy pronunciado. Si usáramos otras funciones como la lineal para la regresión de datos binarios funcionaría muy mal, pues el ajuste lineal no capta bien la forma de los datos, las dos agrupaciones que buscamos separar o clasificar.

Los modelos de regresión logísticos se generan con la función glm() del paquete base R stats, de la siguiente manera.

m <- glm(y ~ x1 + x2 + x3,
           data = my_dataset,
           family = "binomial")

prob <- predict(m, test_dataset, type = "response")

pred <- ifelse(prob > 0.50, 1, 0)

Importante reseñar que la predicción se da en modo de probabilidad, por lo que para evaluar un pronóstico concreto, se debe establecer qué umbral es el que fija el pronostico 0 o 1. En el caso del ejemplo anterior se ha determinado que para pred>0,5 el pronostico es 1.

6.1 Construir modelos glm

Siguiendo con el uso de la base de datos de ejemplo de supervivientes del Titanic, vamos a crear un modelo logístico que pronostique la variable Survived. Podemos ver como se crearon los datos en el apartado de particiones de los datos

Al igual que todos los modelos de aprendizaje, el modelo se compone de una fórmula, y luego se pronostica con la función predict(). En los modelos glm(), los únicos argumentos de predict() son response y terms. El primer caso da directamente la probabilidad de la respuesta y el segundo argumento proporciona los coeficientes de cada término en la fórmula. Si solo queremos obtener un valor de predicción usaremos type = "response".

# Antes hemos cargado los datos del titanic
# echamos un vistazo a los datos
    head(Titanic_data)
##     Class  Sex   Age Survived
## 3     3rd Male Child       No
## 3.1   3rd Male Child       No
## 3.2   3rd Male Child       No
## 3.3   3rd Male Child       No
## 3.4   3rd Male Child       No
## 3.5   3rd Male Child       No
    table(Titanic_data$Survived)
## 
##   No  Yes 
## 1490  711
# creamos una partición para crear un conjunto de test y otro de entrenamiento
    library(caret)
## Loading required package: lattice
## Loading required package: ggplot2
    set.seed(123)
# creamos un vector de particion sobre la variable Survived
# el tamaño de muestra será de 75%
    trainIndex=createDataPartition(Titanic_data$Survived, p=0.70)$Resample1
# definimoslos dos conjuntos de muestra
    d_titanic_train=Titanic_data[trainIndex, ] # conjunto entrenamiento
    d_titanic_test= Titanic_data[-trainIndex, ] # conjunto de test

Una vez tenemos los conjuntos de test y de aprendizaje creamos el modelo, usando la misma simbología que en el caso de los modelos de naive_bayes. La peculiaridad de glm() es que tenemos que identificar un umbral de probabilidad a partir del que consideramos el pronostico 0 o 1.

    # Construimos el modelo de predicción con la función glm
    m_glm <- glm(Survived ~ Class+Sex, data = d_titanic_train, family = "binomial")
    # resumen del modelo
    summary(m_glm) 
## 
## Call:
## glm(formula = Survived ~ Class + Sex, family = "binomial", data = d_titanic_train)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -2.1346  -0.7499  -0.4644   0.7435   2.1356  
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept)  -0.2856     0.1678  -1.702   0.0888 .  
## Class2nd     -1.0257     0.2352  -4.362 1.29e-05 ***
## Class3rd     -1.8870     0.2093  -9.017  < 2e-16 ***
## ClassCrew    -0.8394     0.1911  -4.393 1.12e-05 ***
## SexFemale     2.4557     0.1698  14.463  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1939.3  on 1540  degrees of freedom
## Residual deviance: 1560.7  on 1536  degrees of freedom
## AIC: 1570.7
## 
## Number of Fisher Scoring iterations: 4
    # vemos las predicciones en el conjunto de test
    d_titanic_test$pred<-predict(m_glm, d_titanic_test, type= "response")

    # Hacemos el resumen gráfico del resultado    
        hist(100*d_titanic_test$pred, col="skyblue",
             main=" resultados modelo glm() sobre datos Titanic test",
             xlab="Probabilidad en % de supervivencia",
             ylab="Frecuencia")
    # Marcamos un umbral en el que consideramos el pronostico como donación
    # este umbral lo ponemos en un valor del 60%    
        abline(v= 60,col= "navy", lwd=3)  # marcamos el umbral de supervivencia

        d_titanic_test$pred_final_60 <- ifelse(d_titanic_test$pred > 0.6, 1, 0)
        # resumen de resultados
        table(d_titanic_test$pred_final_60)
## 
##   0   1 
## 575  85
    # podemos calcular el ajuste respecto a los casos reales con esta sencilla formula 
    # antes vamos a cambiar los levels de survived No=0, Yes=1 
        table(d_titanic_test$Survived) # vemos cual es el primero ---> No
## 
##  No Yes 
## 447 213
        levels(d_titanic_test$Survived) <- c(0,1)
        mean(d_titanic_test$pred_final_60 == d_titanic_test$Survived)
## [1] 0.7878788

Como vemos una vez realizado el pronostico podríamos probar diferentes umbrales y ver cual es el que da un mejor resultado con esta metodología.

6.2 curvas ROC y AUC

Estas curvas nos ayudan a controlar el acierto o no de los modelos cuando uno de los eventos es muy raro. Esto implica que predecir el evento opuesto conlleva un gran porcentaje de aciertos, y en cierta forma falsea la utilidad real de la predicción lo que hay que vigilar y entender.

En estos casos es mejor sacrificar los aciertos generales en favor de concentrarlos sobre uno de los resultados, el más raro, el que buscamos distinguir.

Por lo tanto la exactitud de la predicción general es una medida engañosa en el rendimiento de lo que realmente nos interesa. Este es un caso muy común en predicciones binomiales pues un caso, el de éxito puede tener una probabilidad general mucho menor que el de fracaso, y un porcentaje de acierto elevado, puede no tener importancia, pues lo que nos interesa no es acertar los fracasos sino los éxitos.

Las curvas ROC son buenas para evaluar este problema en conjuntos de datos desequilibrados.

Al hacer una gráfica ROC se representa mejor la compensación entre un modelo que es demasiado agresivo y uno que es demasiado pasivo. Lo que interesa es que el área de la curva sea máxima, cercana a 1, por lo que cuanto más se eleve respecto de la linea media mejor.

Estas gráficas se pintan con la libraría pROC. Usaremos dos funciones una para pintar la gráfica y otra que calcula el AUC o área bajo la curva.

    # Cargamos la libraría de graficos ROC
    library(pROC)
## Type 'citation("pROC")' for a citation.
## 
## Attaching package: 'pROC'
## The following objects are masked from 'package:stats':
## 
##     cov, smooth, var
    # Creamos una curva ROC basada en el modelo glm anterior
    ROC_glm60 <- roc(d_titanic_test$Survived, d_titanic_test$pred_final_60)
    
    # Pintamos la grafica ROC
    plot(ROC_glm60, col = "blue")

    #plot(ROC_naive, col = "red")
    
    # Calculamos el area bajo la ROC(AUC)
    auc(ROC_glm60)
## Area under the curve: 0.6787
    d_titanic_test$pred_final_40 <- ifelse(d_titanic_test$pred > 0.4, 1, 0)
    ROC_glm40 <-roc(d_titanic_test$Survived, d_titanic_test$pred_final_40)
    # Pintamos la grafica ROC
    plot(ROC_glm40, col = "red")

    auc(ROC_glm40)
## Area under the curve: 0.7179

Vistos los resultados, el seleccionar un umbral de 40, mejora la predicción de casos positivos de supervivencia.

6.3 Modelos de impacto combinado

En las formulaciones de modelos glm podemos expresar lo que se denominan impactos combinados o interacciones entre variables. Estos casos se dan cuando el efecto combinado de dos variables es muy importante y superior a la combinación lineal de ellas. Es decir el efecto es exponencial y no lineal sobre la variable a predecir.

6.3.1 Ejemplo

Uno de los mejores predictores de donaciones futuras es el historial de donaciones anteriores y cuanto mas recientes, frecuentes y grandes mejor. En términos de comercialización, esto se conoce como R/F/M (Recency Frequency Money).

Es muy probable que el impacto combinado de reciente y frecuencia puede ser mayor que la suma de los efectos por separado, si uno ha dado dinero a una ONG hace muy poco será poco probable que de otra vez enseguida.

Debido a que estos predictores juntos tienen un mayor impacto en la variable dependiente, su efecto conjunto debe modelarse como una interacción. Esto en la formulación del modelo se identifica por un * en lugar de un +.

# Leemos la tabla de datos
    donors<-read.csv("donors.csv",header = TRUE)
    head(donors)
##   donated veteran bad_address age has_children wealth_rating
## 1       0       0           0  60            0             0
## 2       0       0           0  46            1             3
## 3       0       0           0  NA            0             1
## 4       0       0           0  70            0             2
## 5       0       0           0  78            1             1
## 6       0       0           0  NA            0             0
##   interest_veterans interest_religion pet_owner catalog_shopper recency
## 1                 0                 0         0               0 CURRENT
## 2                 0                 0         0               0 CURRENT
## 3                 0                 0         0               0 CURRENT
## 4                 0                 0         0               0 CURRENT
## 5                 0                 1         0               1 CURRENT
## 6                 0                 0         0               0 CURRENT
##    frequency  money
## 1   FREQUENT MEDIUM
## 2   FREQUENT   HIGH
## 3   FREQUENT MEDIUM
## 4   FREQUENT MEDIUM
## 5   FREQUENT MEDIUM
## 6 INFREQUENT MEDIUM
    str(donors)
## 'data.frame':    93462 obs. of  13 variables:
##  $ donated          : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ veteran          : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ bad_address      : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ age              : int  60 46 NA 70 78 NA 38 NA NA 65 ...
##  $ has_children     : int  0 1 0 0 1 0 1 0 0 0 ...
##  $ wealth_rating    : int  0 3 1 2 1 0 2 3 1 0 ...
##  $ interest_veterans: int  0 0 0 0 0 0 0 0 0 0 ...
##  $ interest_religion: int  0 0 0 0 1 0 0 0 0 0 ...
##  $ pet_owner        : int  0 0 0 0 0 0 1 0 0 0 ...
##  $ catalog_shopper  : int  0 0 0 0 1 0 0 0 0 0 ...
##  $ recency          : Factor w/ 2 levels "CURRENT","LAPSED": 1 1 1 1 1 1 1 1 1 1 ...
##  $ frequency        : Factor w/ 2 levels "FREQUENT","INFREQUENT": 1 1 1 1 1 2 2 1 2 2 ...
##  $ money            : Factor w/ 2 levels "HIGH","MEDIUM": 2 1 2 2 2 2 2 2 2 2 ...
# Construimos un modelo complejo
    rfm_model <- glm(donated ~ money + recency* frequency ,data = donors,family = "binomial")
    
# Resumen del modelo RFM 
    summary(rfm_model)
## 
## Call:
## glm(formula = donated ~ money + recency * frequency, family = "binomial", 
##     data = donors)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -0.3696  -0.3696  -0.2895  -0.2895   2.7924  
## 
## Coefficients:
##                                   Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                       -3.01142    0.04279 -70.375   <2e-16 ***
## moneyMEDIUM                        0.36186    0.04300   8.415   <2e-16 ***
## recencyLAPSED                     -0.86677    0.41434  -2.092   0.0364 *  
## frequencyINFREQUENT               -0.50148    0.03107 -16.143   <2e-16 ***
## recencyLAPSED:frequencyINFREQUENT  1.01787    0.51713   1.968   0.0490 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 37330  on 93461  degrees of freedom
## Residual deviance: 36938  on 93457  degrees of freedom
## AIC: 36948
## 
## Number of Fisher Scoring iterations: 6
    #summary(rfm_model)$coefficients
# Calculamos las predicciones del modelo RFM
    rfm_prob <- predict(rfm_model, type = "response")
    head(rfm_prob)
##          1          2          3          4          5          6 
## 0.06601640 0.04691282 0.06601640 0.06601640 0.06601640 0.04105058
# Pintamos la curva ROC para ver el efecto del modelo y calculamos el area AUC
    require(pROC)
    ROC <- roc(donors$donated, rfm_prob)
    plot(ROC, col = "red")

    auc(ROC)
## Area under the curve: 0.5785

6.4 Optimización de un modeloS glm

Cuando a priori no sabemos qué variables tienen más dependencia para crear el modelo una forma de hacerlo es usando la regresión gradual. Esto consiste en aplicar una función que va incrementando las variables y detecta el mejor modelo de regresión.

Para construirlo hacemos lo siguiente:

1 creamos un modelo glm() sin predictores. se hace estableciendo la variable explicativa igual a 1. 2 Se crea otro modelo con todos las variables usando ~ .. 3 Se aplica la función step() entre ambos modelos para realizar una regresión progresiva hacia adelante. Debe indicarse la dirección con direction = "forward" 4 Usamos la función predict() sobre la lista de modelos creados con step

Veamos el ejemplo:

    # 1. Modelo sin predictores
        null_model <- glm(donated ~1, data = donors, family = "binomial")
    
    # 2. modelo completo
        full_model <- glm(donated ~ ., data = donors, family = "binomial")
    
    # 3. funcion step ()
        step_model <- step(null_model, scope = list(lower = null_model, upper = full_model), direction = "forward")
## Start:  AIC=37332.13
## donated ~ 1
## Warning in add1.glm(fit, scope$add, scale = scale, trace = trace, k = k, :
## using the 70916/93462 rows from a combined fit
##                     Df Deviance   AIC
## + frequency          1    28502 37122
## + money              1    28621 37241
## + wealth_rating      1    28705 37326
## + has_children       1    28705 37326
## + age                1    28707 37328
## + interest_veterans  1    28709 37330
## + catalog_shopper    1    28710 37330
## + pet_owner          1    28711 37331
## <none>                    28714 37332
## + interest_religion  1    28712 37333
## + recency            1    28713 37333
## + bad_address        1    28714 37334
## + veteran            1    28714 37334
## 
## Step:  AIC=37024.77
## donated ~ frequency
## Warning in add1.glm(fit, scope$add, scale = scale, trace = trace, k = k, :
## using the 70916/93462 rows from a combined fit
##                     Df Deviance   AIC
## + money              1    28441 36966
## + wealth_rating      1    28493 37018
## + has_children       1    28494 37019
## + interest_veterans  1    28498 37023
## + catalog_shopper    1    28499 37024
## + age                1    28499 37024
## + pet_owner          1    28499 37024
## <none>                    28502 37025
## + interest_religion  1    28501 37026
## + recency            1    28501 37026
## + bad_address        1    28502 37026
## + veteran            1    28502 37027
## 
## Step:  AIC=36949.71
## donated ~ frequency + money
## Warning in add1.glm(fit, scope$add, scale = scale, trace = trace, k = k, :
## using the 70916/93462 rows from a combined fit
##                     Df Deviance   AIC
## + wealth_rating      1    28431 36942
## + has_children       1    28432 36943
## + interest_veterans  1    28438 36948
## + catalog_shopper    1    28438 36949
## + age                1    28439 36949
## + pet_owner          1    28439 36949
## <none>                    28441 36950
## + interest_religion  1    28440 36951
## + recency            1    28441 36951
## + bad_address        1    28441 36951
## + veteran            1    28441 36952
## 
## Step:  AIC=36945.26
## donated ~ frequency + money + wealth_rating
## Warning in add1.glm(fit, scope$add, scale = scale, trace = trace, k = k, :
## using the 70916/93462 rows from a combined fit
##                     Df Deviance   AIC
## + has_children       1    28421 36937
## + interest_veterans  1    28429 36945
## + catalog_shopper    1    28429 36945
## + age                1    28429 36945
## <none>                    28431 36945
## + pet_owner          1    28430 36945
## + interest_religion  1    28431 36947
## + recency            1    28431 36947
## + bad_address        1    28431 36947
## + veteran            1    28431 36947
## 
## Step:  AIC=36938.08
## donated ~ frequency + money + wealth_rating + has_children
## Warning in add1.glm(fit, scope$add, scale = scale, trace = trace, k = k, :
## using the 70916/93462 rows from a combined fit
##                     Df Deviance   AIC
## + pet_owner          1    28418 36937
## + catalog_shopper    1    28418 36937
## + interest_veterans  1    28418 36937
## <none>                    28421 36938
## + interest_religion  1    28420 36939
## + recency            1    28421 36940
## + age                1    28421 36940
## + bad_address        1    28421 36940
## + veteran            1    28421 36940
## 
## Step:  AIC=36932.08
## donated ~ frequency + money + wealth_rating + has_children + 
##     pet_owner
## Warning in add1.glm(fit, scope$add, scale = scale, trace = trace, k = k, :
## using the 70916/93462 rows from a combined fit
##                     Df Deviance   AIC
## <none>                    28418 36932
## + interest_veterans  1    28416 36932
## + catalog_shopper    1    28416 36932
## + age                1    28417 36933
## + recency            1    28417 36934
## + interest_religion  1    28417 36934
## + bad_address        1    28418 36934
## + veteran            1    28418 36934
        summary(step_model)
## 
## Call:
## glm(formula = donated ~ frequency + money + wealth_rating + has_children + 
##     pet_owner, family = "binomial", data = donors)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -0.4023  -0.3625  -0.2988  -0.2847   2.7328  
## 
## Coefficients:
##                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)         -3.05529    0.04556 -67.058  < 2e-16 ***
## frequencyINFREQUENT -0.49649    0.03100 -16.017  < 2e-16 ***
## moneyMEDIUM          0.36594    0.04301   8.508  < 2e-16 ***
## wealth_rating        0.03294    0.01238   2.660 0.007805 ** 
## has_children        -0.15820    0.04707  -3.361 0.000777 ***
## pet_owner            0.11712    0.04096   2.860 0.004243 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 37330  on 93461  degrees of freedom
## Residual deviance: 36920  on 93456  degrees of freedom
## AIC: 36932
## 
## Number of Fisher Scoring iterations: 6
    # estimamos la probabilidad
        step_prob <- predict(step_model, type = "response")
    
    # Pintamos  ROC of the stepwise model
        library(pROC)
        ROC <- roc(donors$donated, step_prob)
        plot(ROC, col = "red")

        auc(ROC)
## Area under the curve: 0.5855

6.5 glmmTMB

Existen algunos paquetes específicos de regresión logística para cuando tenemos datos de partida inflados en ceros. Estos casos son más habituales de lo que podemos pensar, pues muchas veces las variables origen tienen media cero con muchos valores cercanos, y lo que buscamos son casos raros fuera del rango habitual (cero).

La librería library("glmmTMB") tienes algunas características que mejora este tipo de predicciones, y contiene algoritmos denominados zero-inflated generalized linear mixed model o ZIGLMM.

El mejor modelo es el que mejor AIC tiene, para ello tambien es necesario la librería library("bbmle").

Veamos un ejemplo, sobre los datos de muestra de mochuelos (owlets) o polluelos de buho (owl chicks). La base de datos aporta las muestras obtenidas en diferentes nidos durante la cria de mochuelos. Los datos miden el número de llamadas que hace el mochuelo antes de que llegue el progenitor con la comida, y almacena además el tiempo que tarda, el tipo de comida, el lugar del nido y otras variables como el sexo de que llegua a alimentar.

Se registra el número total de llamadas desde el nido, junto con el tamaño total de cría, que se utiliza como compensación para permitir el uso de una respuesta de Poisson.

library("glmmTMB")
library("bbmle")
## Loading required package: stats4
summary(Owls)
##           Nest      FoodTreatment  SexParent    ArrivalTime   
##  Oleyes     : 52   Deprived:320   Female:245   Min.   :21.71  
##  Montet     : 41   Satiated:279   Male  :354   1st Qu.:23.11  
##  Etrabloz   : 34                               Median :24.38  
##  Yvonnand   : 34                               Mean   :24.76  
##  Champmartin: 30                               3rd Qu.:26.25  
##  Lucens     : 29                               Max.   :29.25  
##  (Other)    :379                                              
##  SiblingNegotiation   BroodSize      NegPerChick     logBroodSize  
##  Min.   : 0.00      Min.   :1.000   Min.   :0.000   Min.   :0.000  
##  1st Qu.: 0.00      1st Qu.:4.000   1st Qu.:0.000   1st Qu.:1.386  
##  Median : 5.00      Median :4.000   Median :1.200   Median :1.386  
##  Mean   : 6.72      Mean   :4.392   Mean   :1.564   Mean   :1.439  
##  3rd Qu.:11.00      3rd Qu.:5.000   3rd Qu.:2.500   3rd Qu.:1.609  
##  Max.   :32.00      Max.   :7.000   Max.   :8.500   Max.   :1.946  
## 
head(Owls)
##         Nest FoodTreatment SexParent ArrivalTime SiblingNegotiation
## 1 AutavauxTV      Deprived      Male       22.25                  4
## 2 AutavauxTV      Satiated      Male       22.38                  0
## 3 AutavauxTV      Deprived      Male       22.53                  2
## 4 AutavauxTV      Deprived      Male       22.56                  2
## 5 AutavauxTV      Deprived      Male       22.61                  2
## 6 AutavauxTV      Deprived      Male       22.65                  2
##   BroodSize NegPerChick logBroodSize
## 1         5         0.8     1.609438
## 2         5         0.0     1.609438
## 3         5         0.4     1.609438
## 4         5         0.4     1.609438
## 5         5         0.4     1.609438
## 6         5         0.4     1.609438

Lo primero es hacer algunas transformaciones en los datos:

1. reordenamos los nidos por el orden de la media de negociaciones por polluelo (para pintar mejor)
2. añadimos un log del tamaño de cria
3. renombramos la variable respuesta como NCalls y abreviamos otra FT
# SiblingNegotiation - negociacion entre hermanos
# NegPerChick - negativas por polluelo
Owls <- transform(Owls,Nest=reorder(Nest,NegPerChick),NCalls=SiblingNegotiation,FT=FoodTreatment)
head(Owls)
##         Nest FoodTreatment SexParent ArrivalTime SiblingNegotiation
## 1 AutavauxTV      Deprived      Male       22.25                  4
## 2 AutavauxTV      Satiated      Male       22.38                  0
## 3 AutavauxTV      Deprived      Male       22.53                  2
## 4 AutavauxTV      Deprived      Male       22.56                  2
## 5 AutavauxTV      Deprived      Male       22.61                  2
## 6 AutavauxTV      Deprived      Male       22.65                  2
##   BroodSize NegPerChick logBroodSize NCalls       FT
## 1         5         0.8     1.609438      4 Deprived
## 2         5         0.0     1.609438      0 Satiated
## 3         5         0.4     1.609438      2 Deprived
## 4         5         0.4     1.609438      2 Deprived
## 5         5         0.4     1.609438      2 Deprived
## 6         5         0.4     1.609438      2 Deprived
plot(Owls$Nest,Owls$NCalls, col=rainbow(10))

Ahora ya podemos hacer el modelo glmmTMB. Debemos tener en cuenta que el modelo por defecto usado es un ZIGLMM (ziformula~1), si no queremos usar el inflado de ceros hay que poner (ziformula~0)

Para la formulación de los modelos se toma como estandar la especificación desarrollada en el paquete lme4, y cuyo resumen puede verse aquí de forma estructurada.

fit_zipoisson <- glmmTMB(NCalls~(FT+ArrivalTime)*SexParent+offset(log(BroodSize))+(1|Nest),data=Owls,ziformula=~1,family=poisson)

confint(fit_zipoisson)
##                                      2.5 %      97.5 %    Estimate
## cond.(Intercept)                1.84109659  3.23879725  2.53994692
## cond.FTSatiated                -0.40793938 -0.17427339 -0.29110639
## cond.ArrivalTime               -0.09604799 -0.04010818 -0.06807809
## cond.SexParentMale             -0.43318360  1.33087377  0.44884508
## cond.FTSatiated:SexParentMale  -0.03808278  0.24753288  0.10472505
## cond.ArrivalTime:SexParentMale -0.05736075  0.01456575 -0.02139750
## Nest.cond.Std.Dev.(Intercept)   0.25483237  0.50762131  0.35966420
## zi.zi~(Intercept)              -1.24200277 -0.87306435 -1.05753356
#summary(fit_zipoisson)

# podemos usar otras aproximaciones 
fit_zinbinom <- update(fit_zipoisson,family=nbinom2)
fit_zinbinom1 <- update(fit_zipoisson,family=nbinom1)
fit_zinbinom1_bs <- update(fit_zinbinom1, . ~ (FT+ArrivalTime)*SexParent+
BroodSize+(1|Nest))

# y usar el comparador de AIC para ver el mejor modelo
AICtab(fit_zipoisson,fit_zinbinom,fit_zinbinom1,fit_zinbinom1_bs)
##                  dAIC  df
## fit_zinbinom1_bs   0.0 10
## fit_zinbinom1      1.2 9 
## fit_zinbinom      68.7 9 
## fit_zipoisson    666.0 8