Evaluación de Triaje

Author

Fernando

Carga de datos

Las variables que tenemos son:

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(haven)
library(ggstatsplot)
Warning: package 'ggstatsplot' was built under R version 4.4.1
You can cite this package as:
     Patil, I. (2021). Visualizations with statistical details: The 'ggstatsplot' approach.
     Journal of Open Source Software, 6(61), 3167, doi:10.21105/joss.03167
library(lme4)
Warning: package 'lme4' was built under R version 4.4.1
Loading required package: Matrix

Attaching package: 'Matrix'

The following objects are masked from 'package:tidyr':

    expand, pack, unpack
library(effects)
Warning: package 'effects' was built under R version 4.4.1
Loading required package: carData
lattice theme set by effectsTheme()
See ?effectsTheme for details.
library(ggeffects)
Warning: package 'ggeffects' was built under R version 4.4.1
library(emmeans)
Warning: package 'emmeans' was built under R version 4.4.1
Welcome to emmeans.
Caution: You lose important information if you filter this package's results.
See '? untidy'
library(gtsummary)
Warning: package 'gtsummary' was built under R version 4.4.1
dfRaw <- read_sav("TRIAGE_REDUCIDO.sav") %>% 
  # convertir la columna grupo en factor, con los niveles 0 y 1 convertidos en "Without checklist", "With checklist"
  mutate(Group = factor(as.factor(GRUPO), levels = c(0, 1), labels = c("Without checklist", "With checklist"))) %>% 
  mutate(SEXO= factor(as.factor(SEXO), levels = c(1, 2), labels = c("Hombre", "Mujer"))) %>% 
mutate(PSICOLOGIA= factor(as.factor(PSICOLOGIA), levels = c(0, 1), labels = c("Otro", "Psicólogo")))

Hay variables que se usarán posteriormente y las aparto ahora:

dfTrans = dfRaw %>% select(
                          -starts_with("ARTURO"),
                          -starts_with("MARIO"),
                          -starts_with("LAURA"),
                          -starts_with("JAVIER"),
                          -starts_with("MARIA"),
                          -starts_with("NICOLAS"),
                          -starts_with("MATEO"),
                          -starts_with("TRI_"))

Hay varios actores que han sido evaluados por los sujetos de GRUPO=1. Cambiamos la estructura de los datos para adecuarla a formato tidy y poder hacer análisis de los datos posteriormente:

Los aciertos y errores de los sujetos se han recogido en variables que empiezan por TRI_ y que tienen un valor de 1 si el sujeto ha asignado el triaje correspondiente al actor y un 0 si no lo ha hecho. Vamos a cambiar la estructura de los datos para poder hacer análisis de los datos posteriormente:

dfAciertoTriaje <- dfRaw %>% select(SUJETO, GRUPO,Group,
                             starts_with("TRI_")) %>%
  mutate_all(as.integer) %>% 
  pivot_longer(-c(SUJETO,GRUPO,Group), names_to="ACTOR", values_to = "TRIAJEOK") %>% mutate(ACTOR=str_remove(ACTOR, "TRI_")) 

Por otro lado, independientmenete del acierto, los sujetos decidieron dar una clasificación:

colorActor <- c( "JAVIER"="Green", LAURA="Green", "ARTURO"="Yellow", MARIO="Yellow" ,NICOLAS="Yellow", MARIA="Red", MATEO="Red")


dfTriaje <- dfRaw %>% select(SUJETO, GRUPO, Group,
                             starts_with("PRI_")) %>%
  #Convertir todas las columnas cuyo nombre comienza por "PRI_" en tipo entero
   mutate(across(starts_with("PRI_"), as.integer)) %>% 
pivot_longer(-c(SUJETO,GRUPO, Group), names_to="ACTOR", values_to = "TRIAJE") %>%
  mutate(ACTOR=str_remove(ACTOR, "PRI_")) %>% 
  mutate(Triage=factor(as.factor(TRIAJE), levels = c(1,2,3,4), labels = c("Green", "Yellow","Red","Not labelled"))) %>% 
  mutate(Actor=factor(ACTOR, levels = names(colorActor), labels = sprintf("%s\n(%s)",names(colorActor), colorActor)))
dfTriaje %>%  
ggstatsplot::ggbarstats(y=Group, x=Triage,bf.message = FALSE)+
  scale_fill_manual(values = rev(c("darkgreen","yellow","darkred","grey")))+
  theme(axis.text.x = element_text(size = 11))
Scale for fill is already present.
Adding another scale for fill, which will replace the existing scale.

No esperaba que hubiese valores fuera de rango: 4. Casi todos además han ocurrido en el GRUPO==1. Aparentemente el valor “4” se ha asignado cunado un sujeto no sabía qué decir y parecen haber ocurrido casi todos en el GRUPO 1. Parece que eso se merece su propia variable:

dfTriaje=dfTriaje %>% mutate(NOTRIAJE=as.integer((TRIAJE==4)), TRIAJE=ifelse(TRIAJE==4,NA,TRIAJE)) %>% 
  mutate(Duda=factor(NOTRIAJE, levels = c(0,1), labels = c("No", "Yes")))
dfTriaje %>% 
ggstatsplot::ggbarstats(y=Group, x=Duda,bf.message = FALSE)+
  theme(axis.text.x = element_text(size = 12))

Vamos a estudiar la situación a nivel de sujetos: Los que han tenido dudas en algún caso frente a los que no lo han tenido en ninguno:

dfTriaje %>% group_by(Group,SUJETO) %>% summarise(`Ever have doubts`=factor(as.integer(sum(NOTRIAJE)>=1),levels=c(0,1), labels=c("Never", "Ever"))) %>% 
  ggstatsplot::ggbarstats(y=Group, x=`Ever have doubts`,bf.message = FALSE)+
  theme(axis.text.x = element_text(size = 11))
`summarise()` has grouped output by 'Group'. You can override using the
`.groups` argument.

ITEMS

dfITEM= tribble(~ITEM, ~Item,
1, "Item 1",
2 , "Ideas suicidio",
3, "Ideas agresivas",
4, "Item 4",
5, "Item 5",
6, "Recent death",
7, "Item 7",
8, "Item 8",
9, "Psychopharmaceuticals",
10, "Item 10",
11,"Sentir culpa") %>% mutate(ITEM=as.integer(ITEM))

dfITEM
# A tibble: 11 × 2
    ITEM Item                 
   <int> <chr>                
 1     1 Item 1               
 2     2 Ideas suicidio       
 3     3 Ideas agresivas      
 4     4 Item 4               
 5     5 Item 5               
 6     6 Recent death         
 7     7 Item 7               
 8     8 Item 8               
 9     9 Psychopharmaceuticals
10    10 Item 10              
11    11 Sentir culpa         

ANÁLISIS DEL ACTOR/TIPO DE CASO USANDO EL GRUPO 1

Me gustaría saber si ha tenido algo que ver el tipo de caso a estudiar (ACTOR) via sus ITEMS. Para eso necesitamos datos extra:

dfActor <- dfRaw %>% filter(GRUPO==1) %>%
                     select(SUJETO, 
                            starts_with("ARTURO"),
                            starts_with("MARIO"),
                            starts_with("LAURA"),
                            starts_with("JAVIER"),
                            starts_with("MARIA"),
                            starts_with("NICOLAS"),
                            starts_with("MATEO"))



colorActor <- c( "JAVIER"="Green", LAURA="Green", "ARTURO"="Yellow", MARIO="Yellow" ,NICOLAS="Yellow", MARIA="Red", MATEO="Red")




dfLong=dfActor %>% pivot_longer(-c(SUJETO),values_to="PRESENTE", names_to="ITEM") %>% separate(ITEM, into = c("ACTOR", "ITEM")) %>% 
mutate(PRESENTE=as.integer(PRESENTE==1),
       Presente=factor(as.factor(PRESENTE), levels = c(0,1), labels = c("No", "Yes")))


dfLong2 <- dfLong %>% inner_join(dfTriaje, by=c("SUJETO", "ACTOR")) %>%
  filter(!str_detect(ITEM,"C")) %>% mutate(ITEM=as.integer(ITEM)) %>% 
  left_join(dfITEM, by="ITEM") %>% 
  mutate(Actor=factor(ACTOR, levels = names(colorActor), labels = sprintf("%s\n(%s)",names(colorActor), colorActor)))
###ZZZZZZZZZZZZZZZZZZZZZZZ
dfActorItem=openxlsx::read.xlsx("tablaActores-ITEM.xlsx",1) %>% mutate(ITEM=as.integer(ITEM),PRESENTEREAL=as.integer(PRESENTE)) %>% select(ACTOR,ITEM,PRESENTEREAL)
  

itemDiscriminante <- c(2,3,6,9,11)

dfActorItemDiscriminante <- dfActorItem %>% filter(ITEM %in% itemDiscriminante) %>% filter(PRESENTEREAL==1) %>% select(ACTOR,ITEM)
dfLong3=dfLong2 %>%  inner_join(dfActorItem,by = join_by(ACTOR, ITEM)) %>% mutate(itemOK=as.integer(PRESENTE==PRESENTEREAL), itemKO=as.integer(PRESENTE!=PRESENTEREAL))
dfLong4 = dfLong3 %>% 
  mutate(ITEM_PRESENTEREAL=sprintf("%02d-%d",ITEM,PRESENTEREAL),
         Presentereal=factor(PRESENTEREAL, levels = c(0,1), labels = c("No", "Yes")),
         Item_Presentereal=sprintf("%s: %s",Item, Presentereal),
                   ACIERTO=as.integer(!is.na(PRESENTE) & PRESENTE==PRESENTEREAL)) %>%
  mutate(Success=factor(as.factor(ACIERTO), levels = c(0,1), labels = c("No", "Yes")))
dfLong4 %>% inner_join(dfActorItemDiscriminante %>% select(ITEM), by = join_by( ITEM)) %>%  
  select(SUJETO,ACTOR,Item_Presentereal,Success) %>% arrange(ACTOR,Item_Presentereal) %>% 
  ggbarstats(y=Item_Presentereal, x=Success, bf.message = FALSE)+
  theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))+xlab("")+
  #Aumentar la fuente en xticks
  theme(axis.text.x = element_text(size = 12))

No es relevante en ese gráfico el cálculo superior de la significancia estadística.

Creo que es mejor extraer lo relevante en dos gráficos:

p1 <- dfLong4 %>% filter(ITEM==9) %>%  
  select(SUJETO,ACTOR,Item_Presentereal,Success,Presentereal) %>% arrange(ACTOR,Item_Presentereal) %>% 
  ggbarstats(y=Presentereal, x=Success, bf.message = FALSE)+xlab("Psychopharmaceuticals")+
   theme(axis.text.x = element_text(size = 12))
p1

Para la característica 6:

p2 <- dfLong4 %>% filter(ITEM==6) %>%  
  select(SUJETO,ACTOR,Item_Presentereal,Success,Presentereal) %>% arrange(ACTOR,Item_Presentereal) %>% 
  ggbarstats(y=Presentereal, x=Success, bf.message = FALSE)+xlab("Recent death")+
 theme(axis.text.x = element_text(size = 12))
p2

#unir gráficos p1 y p2 en uno solo
gridExtra::grid.arrange(p1,p2, nrow=1)

Para el resto no influye en la tasa de acierto el que esté presente o que no.

Análisis de triajes

Análisis actor a actor

En primer lugar comenzamos separando las respuestas por actores, ya que cada uno reflejaba aspectos diferentes y deberían objetivamente tener un valor de triaje diferente.

Realmente estos actores tienen una puntuación objetiva que los sujetos deberían haber asignado:

dfTriObj=tibble( ACTOR=c("ARTURO", "MARIO", "LAURA", "JAVIER", "MARIA", "NICOLAS", "MATEO"),
                 TRIAJEOBJ=c(2, 2, 1, 1, 3, 1, 3))
dfTriObj
# A tibble: 7 × 2
  ACTOR   TRIAJEOBJ
  <chr>       <dbl>
1 ARTURO          2
2 MARIO           2
3 LAURA           1
4 JAVIER          1
5 MARIA           3
6 NICOLAS         1
7 MATEO           3

Vamos a evaluar los triajes que han hecho los individuos con respecto a los triajes objetivos y vamos a anotar las diferencias (si se han pasado, quedado cortos o acertado):

dfCompTriaje=dfTriaje %>% inner_join(dfTriObj, by="ACTOR") %>% 
  mutate(DIFERENCIA=TRIAJE-TRIAJEOBJ) %>% 
  mutate(`Triage results`=case_when(
    DIFERENCIA==2 ~ "Overstimated 2 categoríes",
    DIFERENCIA==1 ~ "Overstimated 1 category",
    DIFERENCIA==-1 ~ "Underestimated 2 categories",
    DIFERENCIA==-2 ~ "Underestimated 1 category",
    TRUE ~ "Tagged with correct category")) %>%
  #reordenar niveles
  mutate(`Triage results`=forcats::fct_relevel(`Triage results`,  "Underestimated 2 categories", "Underestimated 1 category", "Tagged with correct category", "Overstimated 1 category", "Overstimated 2 categoríes")) %>% 
  mutate(`Triage results`=ordered(`Triage results`))

Me gustaría ver comparar los aciertos según GRUPO según el ACTOR, que sabemos que está muy relacionado algunos de ellos con ciertas características que estaban presentes en los vídeos:

p3<-dfCompTriaje  %>% 
  ggbarstats(y=Actor, x=`Triage results`, bf.message = FALSE)+
  theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))+xlab("")+
  # usar paleta ordinal para el color
  scale_fill_manual(values = c("darkblue", "blue", "gray", "orange", "darkorange"))
Scale for fill is already present.
Adding another scale for fill, which will replace the existing scale.
p3

Los aciertos corresponden al cero (VIOLETA), que desde luego no es tan abundante como esperaba. En ocasiones aciertan incluso peor que eligiendo al azar (vease el caso de ARTURO)

Los valores positivos indican que el Sujeto se ha pasado en el valor del triaje con respecto al valor objetivo, y los negativos representan lo contrario. Solo en el caso de MARIO la gente se equivoca de forma simétrica. En los demás (salvo en el de NICOLAS) todo el mundo que se equivoca, o bien se pasa o bien se queda corto. En el caso de NICOLAS, la gente tiende a quedarse corta aunque un 6% se pasa. Estaría bien pensar sobre esto.

Vamos a desglosar esos patrones según GRUPO:

p3<- dfCompTriaje %>% filter(GRUPO==0)  %>% 
   ggbarstats(y=Actor, x=`Triage results`, bf.message = FALSE, title="Cases without checklist")+
  theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))+xlab("")+
  # usar paleta ordinal para el color
  scale_fill_manual(values = c("darkblue", "blue", "gray", "orange", "darkorange"))
Scale for fill is already present.
Adding another scale for fill, which will replace the existing scale.
p3

p4<- dfCompTriaje %>% filter(GRUPO==1)  %>% 
   ggbarstats(y=Actor, x=`Triage results`, bf.message = FALSE, title="Cases with checklist")+
  theme(axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5))+xlab("")+
  # usar paleta ordinal para el color
  scale_fill_manual(values = c("darkblue", "blue", "gray", "orange", "darkorange"))
Scale for fill is already present.
Adding another scale for fill, which will replace the existing scale.
p4

Los dos juntos:

#unir gráficos p3 y p4 en uno solo
gridExtra::grid.arrange(p3,p4, nrow=2)

Comparaciones de resultados totales en triajes

Ahora solo nos interesa saber qué resultado total hemos tenido en los triajes. Se puede evaluar de dos formas en principio: Mirando aciertos/errores o bien viendo el error medio (en valor absoluto) cometido donde error 0 es acierto.

dfTriajeTotal <- dfCompTriaje%>% 
  filter(complete.cases(.)) %>%
  group_by(GRUPO,Group,SUJETO) %>% 
  summarise(PCTACIERTOS=100*sum(DIFERENCIA==0)/sum(!is.na(DIFERENCIA)),
            ERRORMEDIO=mean(abs(DIFERENCIA)),.groups = "drop") 

Comparemos ambos grupos en ambas medidas:

dfTriajeTotal %>% 
  ggbetweenstats(x=Group, y=PCTACIERTOS, bf.message = FALSE)+
  ylab("Hit percentage")+xlab("")

dfTriajeTotal %>% 
  ggbetweenstats(x=Group, y=ERRORMEDIO, bf.message = FALSE)+
    ylab("Error medio cometido")+xlab("")

Modelo multinivel

EN este usamos otra base de datos. Consideramos a los actores como miembros de un conjunto infinito de actores random que van a ser evaluados por los sujetos. Con ellos podemos acertar o no en el triaje.

La base de datos sería la siguiente:

dfMultinivel=dfCompTriaje %>% 
  select(Group,SUJETO,ACTOR,DIFERENCIA) %>% 
  mutate(ACIERTO=as.integer(DIFERENCIA==0))  %>% 
  inner_join(dfTrans %>% 
               select(Group,SUJETO,PROFESION,SEXO,EDAD,TMMS_ATENCION,TMMS_CLARIDAD,TMMS_REGULACION,RESILIENCIA,PSICOLOGIA, TOTALCOMP)) 
Joining with `by = join_by(Group, SUJETO)`

Ahora hacemos el modelo de regresión logístico multinivel usando el ACTOR como un factor RANDOM:

modeloMultinivel=glmer(ACIERTO ~ Group+SEXO+EDAD+TMMS_ATENCION+TMMS_CLARIDAD+TMMS_REGULACION+RESILIENCIA+PSICOLOGIA+#TOTALCOMP+
                         (1|ACTOR), data = dfMultinivel, family = binomial(link = "logit"))

summary(modeloMultinivel)
Generalized linear mixed model fit by maximum likelihood (Laplace
  Approximation) [glmerMod]
 Family: binomial  ( logit )
Formula: ACIERTO ~ Group + SEXO + EDAD + TMMS_ATENCION + TMMS_CLARIDAD +  
    TMMS_REGULACION + RESILIENCIA + PSICOLOGIA + (1 | ACTOR)
   Data: dfMultinivel

     AIC      BIC   logLik deviance df.resid 
  1046.0   1092.3   -513.0   1026.0      751 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-1.9047 -0.9356 -0.6215  0.9677  1.5628 

Random effects:
 Groups Name        Variance Std.Dev.
 ACTOR  (Intercept) 0.09721  0.3118  
Number of obs: 761, groups:  ACTOR, 7

Fixed effects:
                     Estimate Std. Error z value Pr(>|z|)   
(Intercept)         -0.211819   0.622685  -0.340  0.73373   
GroupWith checklist  0.462874   0.156869   2.951  0.00317 **
SEXOMujer           -0.092525   0.170230  -0.544  0.58676   
EDAD                 0.003273   0.006861   0.477  0.63332   
TMMS_ATENCION        0.031009   0.023070   1.344  0.17890   
TMMS_CLARIDAD        0.021772   0.026276   0.829  0.40733   
TMMS_REGULACION      0.030604   0.025183   1.215  0.22426   
RESILIENCIA         -0.045663   0.016807  -2.717  0.00659 **
PSICOLOGIAPsicólogo  0.170821   0.160448   1.065  0.28703   
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Warning in abbreviate(rn, minlength = 11): abbreviate used with non-ASCII chars

Correlation of Fixed Effects:
Warning in abbreviate(rn, minlength = 6): abbreviate used with non-ASCII chars
            (Intr) GrpWtc SEXOMj EDAD   TMMS_A TMMS_C TMMS_R RESILI
GrpWthchckl -0.050                                                 
SEXOMujer   -0.242 -0.097                                          
EDAD        -0.631 -0.237  0.260                                   
TMMS_ATENCI -0.336  0.085 -0.313  0.245                            
TMMS_CLARID -0.110 -0.090  0.030 -0.048 -0.299                     
TMMS_REGULA -0.158  0.005  0.117  0.176 -0.008 -0.174              
RESILIENCIA -0.343  0.055  0.070 -0.075 -0.103 -0.214 -0.484       
PSICOLOGIAP  0.072  0.091 -0.010 -0.106  0.092 -0.139  0.045 -0.142

El estilo de publicaciones es algo así:

gtsummary::tbl_regression(modeloMultinivel, digits=3, tidy_fun = broom.mixed::tidy)

Characteristic

log(OR)

1

95% CI

1

p-value

Group


    Without checklist
    With checklist 0.46 0.16, 0.77 0.003
SEXO


    Hombre
    Mujer -0.09 -0.43, 0.24 0.6
EDAD 0.00 -0.01, 0.02 0.6
FACTOR ATENCIÓN INT. EMOCIONAL 0.03 -0.01, 0.08 0.2
FACTOR CLARIDAD INT. EMOCIONAL 0.02 -0.03, 0.07 0.4
FACTOR REGULACIÓN INT. EMOCIONAL 0.03 -0.02, 0.08 0.2
RESILIENCIA -0.05 -0.08, -0.01 0.007
PSICOLOGIA


    Otro
    Psicólogo 0.17 -0.14, 0.49 0.3
ACTOR.sd__(Intercept) 0.31

1

OR = Odds Ratio, CI = Confidence Interval

O así:

gtsummary::tbl_regression(modeloMultinivel, digits=3, tidy_fun = broom.mixed::tidy,exponentiate = TRUE)

Characteristic

OR

1

95% CI

1

p-value

Group


    Without checklist
    With checklist 1.59 1.17, 2.16 0.003
SEXO


    Hombre
    Mujer 0.91 0.65, 1.27 0.6
EDAD 1.00 0.99, 1.02 0.6
FACTOR ATENCIÓN INT. EMOCIONAL 1.03 0.99, 1.08 0.2
FACTOR CLARIDAD INT. EMOCIONAL 1.02 0.97, 1.08 0.4
FACTOR REGULACIÓN INT. EMOCIONAL 1.03 0.98, 1.08 0.2
RESILIENCIA 0.96 0.92, 0.99 0.007
PSICOLOGIA


    Otro
    Psicólogo 1.19 0.87, 1.62 0.3
ACTOR.sd__(Intercept) 0.31

1

OR = Odds Ratio, CI = Confidence Interval

Y si quieres que las tablas tengan el número de aciertos para cada nivel de una variable y dar más detalle como los q-valores (p-valores corregidos para comparaciones múltiples) y factor de inflación de la varianza (VIF) por si queréis comentar que no había mucha colinealidad entre las variables explicativas. Más detalles que esto no se suele dar. Podéis borrar las columnas que no os gusten:

gtsummary::tbl_regression(modeloMultinivel, digits=3, tidy_fun = broom.mixed::tidy,exponentiate = TRUE) %>% 
  add_significance_stars(
    hide_p=F,hide_se=T, hide_ci=F) %>%
  bold_p() %>% 
  add_q() %>% 
  add_vif() %>% 
  add_n(location="level") %>% 
  add_nevent(location="level") 

Characteristic

N

Event N

OR

1,2

95% CI

2

p-value

q-value

3

VIF

2
Group





1.1
    Without checklist 348 148


    With checklist 413 223 1.59** 1.17, 2.16 0.003 0.025
SEXO





1.3
    Hombre 368 180


    Mujer 393 191 0.91 0.65, 1.27 0.6 0.6
EDAD 761 371 1.00 0.99, 1.02 0.6 0.6 1.4
FACTOR ATENCIÓN INT. EMOCIONAL 761 371 1.03 0.99, 1.08 0.2 0.4 1.5
FACTOR CLARIDAD INT. EMOCIONAL 761 371 1.02 0.97, 1.08 0.4 0.5 1.4
FACTOR REGULACIÓN INT. EMOCIONAL 761 371 1.03 0.98, 1.08 0.2 0.4 1.6
RESILIENCIA 761 371 0.96** 0.92, 0.99 0.007 0.026 1.7
PSICOLOGIA





1.1
    Otro 478 229


    Psicólogo 283 142 1.19 0.87, 1.62 0.3 0.5
ACTOR.sd__(Intercept) 761 371 0.31



1

p<0.05; p<0.01; p<0.001

2

OR = Odds Ratio, CI = Confidence Interval, VIF = Variance Inflation Factor

3

False discovery rate correction for multiple testing

O así:

sjPlot::tab_model(modeloMultinivel)
  ACIERTO
Predictors Odds Ratios CI p
(Intercept) 0.81 0.24 – 2.74 0.734
Group: With checklist 1.59 1.17 – 2.16 0.003
SEXO: Mujer 0.91 0.65 – 1.27 0.587
EDAD 1.00 0.99 – 1.02 0.633
FACTOR ATENCIÓN INT.
EMOCIONAL
1.03 0.99 – 1.08 0.179
FACTOR CLARIDAD INT.
EMOCIONAL
1.02 0.97 – 1.08 0.407
FACTOR REGULACIÓN INT.
EMOCIONAL
1.03 0.98 – 1.08 0.224
RESILIENCIA 0.96 0.92 – 0.99 0.007
PSICOLOGIA: Psicólogo 1.19 0.87 – 1.62 0.287
Random Effects
σ2 3.29
τ00 ACTOR 0.10
ICC 0.03
N ACTOR 7
Observations 761
Marginal R2 / Conditional R2 0.032 / 0.060

Una forma de mostrar gráficamente qué significa la parte interesante del modelo es centrarnos en el efecto del grupo en la probabilidad de acierto. Para ello, podemos usar la función ggpredict del paquete ggeffects para generar predicciones.

# Generar predicciones usando ggpredict
predicciones <- ggpredict(modeloMultinivel, terms = "Group")

# Graficar las predicciones
plot(predicciones) + 
  theme_minimal() + 
  labs(title = "Efecto del grupo en la probabilidad de acierto",
       x = "Group",
       y = "Probabilidad de acierto")+
  coord_cartesian(ylim=c(0.3,0.65))

emmeans(modeloMultinivel, pairwise ~ Group,type="response", infer=T)$emmeans 
 Group              prob     SE  df asymp.LCL asymp.UCL null z.ratio p.value
 Without checklist 0.431 0.0402 Inf     0.354     0.510  0.5  -1.704  0.0883
 With checklist    0.546 0.0393 Inf     0.468     0.621  0.5   1.157  0.2473

Results are averaged over the levels of: SEXO, PSICOLOGIA 
Confidence level used: 0.95 
Intervals are back-transformed from the logit scale 
Tests are performed on the logit scale 

Esos “p” de ahí tratan sobre si la probabilidad de acertar se aleja del 50%, cosa que no es relevante, pero lo pongo por si os interesa tener el intervalo de confianza de la probabilidad de acertar en forma numérica en lugar de gráfica.

Y de nuevo la OR en forma de solo valores numéricos para la variable interesante. Lo pongo así por tener un doble chequeo de que lo haga como lo haga da lo mismo.

emmeans(modeloMultinivel, pairwise ~ Group,type="response", infer=T) %>% 
  pairs(reverse=T,infer=T)
 contrast                           odds.ratio    SE  df asymp.LCL asymp.UCL
 With checklist / Without checklist       1.59 0.249 Inf      1.17      2.16
 null z.ratio p.value
    1   2.951  0.0032

Results are averaged over the levels of: SEXO, PSICOLOGIA 
Confidence level used: 0.95 
Intervals are back-transformed from the log odds ratio scale 
Tests are performed on the log odds ratio scale