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)
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)
Loading required package: Matrix

Attaching package: 'Matrix'

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

    expand, pack, unpack
dfRaw <- read_sav("TRIAGE_REDUCIDO.sav")
dfRaw %>% names()
  [1] "SUJETO"          "GRUPO"           "TITULADO"        "PROFESION"      
  [5] "NACIDO"          "SEXO"            "PAIS"            "EXPERIENCIA"    
  [9] "ARTURO_1"        "ARTURO_2"        "ARTURO_3"        "ARTURO_4"       
 [13] "ARTURO_5"        "ARTURO_6"        "ARTURO_7"        "ARTURO_8"       
 [17] "ARTURO_9"        "ARTURO_10"       "ARTURO_11"       "PRI_ARTURO"     
 [21] "MARIO_1"         "MARIO_2"         "MARIO_3"         "MARIO_4"        
 [25] "MARIO_5"         "MARIO_6"         "MARIO_7"         "MARIO_8"        
 [29] "MARIO_9"         "MARIO_10"        "MARIO_11"        "PRI_MARIO"      
 [33] "LAURA_1"         "LAURA_2"         "LAURA_3"         "LAURA_4"        
 [37] "LAURA_5"         "LAURA_6"         "LAURA_7"         "LAURA_8"        
 [41] "LAURA_9"         "LAURA_10"        "LAURA_11"        "PRI_LAURA"      
 [45] "JAVIER_1"        "JAVIER_2"        "JAVIER_3"        "JAVIER_4"       
 [49] "JAVIER_5"        "JAVIER_6"        "JAVIER_7"        "JAVIER_8"       
 [53] "JAVIER_9"        "JAVIER_10"       "JAVIER_11"       "PRI_JAVIER"     
 [57] "MARIA_1"         "MARIA_2"         "MARIA_3"         "MARIA_4"        
 [61] "MARIA_5"         "MARIA_6"         "MARIA_7"         "MARIA_8"        
 [65] "MARIA_9"         "MARIA_10"        "MARIA_11"        "PRI_MARIA"      
 [69] "NICOLAS_1"       "NICOLAS_2"       "NICOLAS_3"       "NICOLAS_4"      
 [73] "NICOLAS_5"       "NICOLAS_6"       "NICOLAS_7"       "NICOLAS_8"      
 [77] "NICOLAS_9"       "NICOLAS_10"      "NICOLAS_11"      "PRI_NICOLAS"    
 [81] "MATEO_1"         "MATEO_2"         "MATEO_3"         "MATEO_4"        
 [85] "MATEO_5"         "MATEO_6"         "MATEO_7"         "MATEO_8"        
 [89] "MATEO_9"         "MATEO_10"        "MATEO_11"        "PRI_MATEO"      
 [93] "CUALID1"         "CUALID2"         "CUALID3"         "CUALID4"        
 [97] "CUALID5"         "CUALID6"         "CUALID7"         "CUALID8"        
[101] "CUALID9"         "CUALID10"        "CD1"             "CD2"            
[105] "CD3"             "CD4"             "CD5"             "CD6"            
[109] "CD7"             "CD8"             "CD9"             "CD10"           
[113] "TMMS1"           "TMMS2"           "TMMS3"           "TMMS4"          
[117] "TMMS5"           "TMMS6"           "TMMS7"           "TMMS8"          
[121] "TMMS9"           "TMMS10"          "TMMS11"          "TMMS12"         
[125] "EDAD"            "ARTURO_1C"       "ARTURO_2C"       "ARTURO_3C"      
[129] "ARTURO_4C"       "ARTURO_5C"       "ARTURO_6C"       "ARTURO_7C"      
[133] "ARTURO_8C"       "ARTURO_9C"       "ARTURO_10C"      "ARTURO_11C"     
[137] "CRI_ARTURO"      "MARIO_1C"        "MARIO_2C"        "MARIO_3C"       
[141] "MARIO_4C"        "MARIO_5C"        "MARIO_6C"        "MARIO_7C"       
[145] "MARIO_8C"        "MARIO_9C"        "MARIO_10C"       "MARIO_11C"      
[149] "CRI_MARIO"       "LAURA_1C"        "LAURA_2C"        "LAURA_3C"       
[153] "LAURA_4C"        "LAURA_5C"        "LAURA_6C"        "LAURA_7C"       
[157] "LAURA_8C"        "LAURA_9C"        "LAURA_10C"       "LAURA_11C"      
[161] "CRI_LAURA"       "VAR00009"        "VAR00010"        "VAR00012"       
[165] "VAR00011"        "MARIA_1C"        "MARIA_2C"        "MARIA_3C"       
[169] "MARIA_4C"        "MARIA_5C"        "MARIA_6C"        "MARIA_7C"       
[173] "MARIA_8C"        "MARIA_9C"        "MARIA_10C"       "MARIA_11C"      
[177] "CRI_MARIA"       "NICOLAS_1C"      "NICOLAS_2C"      "NICOLAS_3C"     
[181] "NICOLAS_4C"      "NICOLAS_5C"      "NICOLAS_6C"      "NICOLAS_7C"     
[185] "NICOLAS_8C"      "NICOLAS_9C"      "NICOLAS_10C"     "NICOLAS_11C"    
[189] "CRI_NICOLAS"     "MATEO_1C"        "MATEO_2C"        "MATEO_3C"       
[193] "MATEO_4C"        "MATEO_5C"        "MATEO_6C"        "MATEO_7C"       
[197] "MATEO_8C"        "MATEO_9C"        "MATEO_10C"       "MATEO_11C"      
[201] "CRI_MATEO"       "TRI_ARTURO"      "TRI_MARIO"       "TRI_LAURA"      
[205] "TRI_JAVIER"      "TRI_MARIA"       "TRI_NICOLAS"     "TRI_MATEO"      
[209] "ACIERTOS"        "TMMS_ATENCION"   "TMMS_CLARIDAD"   "TMMS_REGULACION"
[213] "AC_VERDES"       "AC_AMARILLOS"    "AC_ROJOS"        "RESILIENCIA"    
[217] "TOTALCOMP"       "PSICOLOGIA"     

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,
                             starts_with("TRI_")) %>%
  mutate_all(as.integer) %>% 
  pivot_longer(-c(SUJETO,GRUPO), 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:

dfTriaje <- dfRaw %>% select(SUJETO, GRUPO,
                             starts_with("PRI_")) %>%
  mutate_all(as.integer) %>% 
  pivot_longer(-c(SUJETO,GRUPO), names_to="ACTOR", values_to = "TRIAJE") %>% mutate(ACTOR=str_remove(ACTOR, "PRI_")) 

Los valores de TRIAJE deberían tomar valores entre 1 y 3. Veamos las distribución por GRUPO:

dfTriaje %>% count(GRUPO,TRIAJE)
# A tibble: 8 × 3
  GRUPO TRIAJE     n
  <int>  <int> <int>
1     0      1    79
2     0      2   155
3     0      3   128
4     0      4     2
5     1      1   147
6     1      2   176
7     1      3    90
8     1      4    42
dfTriaje %>% mutate(GRUPO=as.factor(GRUPO),TRIAJE=as.factor(TRIAJE)) %>% 
ggstatsplot::ggbarstats(y=GRUPO, x=TRIAJE)

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))
dfTriaje %>% mutate(GRUPO=as.factor(GRUPO),NOTRIAJE=as.factor(NOTRIAJE)) %>% 
ggstatsplot::ggbarstats(y=GRUPO, x=NOTRIAJE,bf.message = FALSE)

Desde luego los del GRUPO 1, dudan más que los del grupo 0. Me parece que podríais intentar explicarlo tal vez de este modo:

Había una vez un cienpiés que se movía con gracia y sin esfuerzo, asombrando a todos los animales con su coordinación perfecta. Un día, una rana, intrigada por la habilidad del centípedo, le preguntó: “¿Cómo logras coordinar todas tus patas sin tropezar nunca?” El centípedo, que nunca antes había pensado en cómo lo hacía, empezó a reflexionar sobre la pregunta. Intentó concentrarse en el movimiento de cada una de sus patas, pero al hacerlo, se confundió y tropezó, cayendo al suelo.

listaPorACTOR= dfTriaje %>% split(.$ACTOR) 


listaGraficos = listaPorACTOR%>% map2(names(listaPorACTOR), ~ {.x %>% ggstatsplot::ggbarstats(y=GRUPO, x=NOTRIAJE,bf.message = FALSE)+ggtitle(.y)})

#Crear con la lista de Gráficos uno solo de dos columnas
listaGraficos
$ARTURO


$JAVIER


$LAURA


$MARIA


$MARIO


$MATEO


$NICOLAS

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(GRUPO,SUJETO) %>% summarise(NOTRIAJE=sum(NOTRIAJE)>=1) %>% 
  ggstatsplot::ggbarstats(y=GRUPO, x=NOTRIAJE,bf.message = FALSE)
`summarise()` has grouped output by 'GRUPO'. You can override using the
`.groups` argument.

También podemos estudiar la cantidad de casos en que los participantes no se han atrevido a responder:

dfTriaje %>% mutate(GRUPO=as.factor(GRUPO)) %>% group_by(GRUPO,SUJETO) %>% summarise(NOTRIAJE=sum(NOTRIAJE),.groups = "drop" ) %>% mutate(DUDA=as.factor(NOTRIAJE>=1)) %>%  
ggplot(aes(x=NOTRIAJE,fill=DUDA))+geom_bar()+
  facet_wrap(~GRUPO)

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"))








dfLong=dfActor %>% pivot_longer(-c(SUJETO),values_to="PRESENTE", names_to="ITEM") %>% separate(ITEM, into = c("ACTOR", "ITEM")) %>% 
mutate(PRESENTE=as.integer(PRESENTE==1))


dfLong2 <- dfLong %>% inner_join(dfTriaje, by=c("SUJETO", "ACTOR")) %>%
  filter(!str_detect(ITEM,"C")) %>% mutate(ITEM=as.integer(ITEM))
dfActorItem=openxlsx::read.xlsx("tablaActores-ITEM.xlsx",1) %>% mutate(ITEM=as.integer(ITEM),PRESENTEREAL=as.integer(PRESENTE)) %>% select(ACTOR,ITEM,PRESENTEREAL) 
dfActorItem
     ACTOR ITEM PRESENTEREAL
1   ARTURO    1            1
2   ARTURO    2            0
3   ARTURO    3            0
4   ARTURO    4            0
5   ARTURO    5            0
6   ARTURO    6            0
7   ARTURO    7            0
8   ARTURO    8            0
9   ARTURO    9            1
10  ARTURO   10            0
11  ARTURO   11            0
12  JAVIER    1            1
13  JAVIER    2            0
14  JAVIER    3            0
15  JAVIER    4            0
16  JAVIER    5            0
17  JAVIER    6            0
18  JAVIER    7            0
19  JAVIER    8            0
20  JAVIER    9            0
21  JAVIER   10            0
22  JAVIER   11            0
23   LAURA    1            1
24   LAURA    2            0
25   LAURA    3            0
26   LAURA    4            0
27   LAURA    5            0
28   LAURA    6            0
29   LAURA    7            0
30   LAURA    8            0
31   LAURA    9            0
32   LAURA   10            0
33   LAURA   11            0
34   MARIA    1            1
35   MARIA    2            1
36   MARIA    3            0
37   MARIA    4            0
38   MARIA    5            0
39   MARIA    6            0
40   MARIA    7            0
41   MARIA    8            0
42   MARIA    9            0
43   MARIA   10            0
44   MARIA   11            0
45   MARIO    1            1
46   MARIO    2            0
47   MARIO    3            0
48   MARIO    4            0
49   MARIO    5            0
50   MARIO    6            1
51   MARIO    7            0
52   MARIO    8            0
53   MARIO    9            0
54   MARIO   10            0
55   MARIO   11            1
56   MATEO    1            1
57   MATEO    2            0
58   MATEO    3            1
59   MATEO    4            0
60   MATEO    5            0
61   MATEO    6            0
62   MATEO    7            0
63   MATEO    8            0
64   MATEO    9            0
65   MATEO   10            0
66   MATEO   11            0
67 NICOLAS    1            1
68 NICOLAS    2            0
69 NICOLAS    3            0
70 NICOLAS    4            0
71 NICOLAS    5            0
72 NICOLAS    6            0
73 NICOLAS    7            0
74 NICOLAS    8            0
75 NICOLAS    9            0
76 NICOLAS   10            0
77 NICOLAS   11            0

Me gustaría saber cómo se han distribuido las características de los actores en los items:

dfActorItem %>% pivot_wider(names_from="ITEM",values_from="PRESENTEREAL")
# A tibble: 7 × 12
  ACTOR     `1`   `2`   `3`   `4`   `5`   `6`   `7`   `8`   `9`  `10`  `11`
  <chr>   <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
1 ARTURO      1     0     0     0     0     0     0     0     1     0     0
2 JAVIER      1     0     0     0     0     0     0     0     0     0     0
3 LAURA       1     0     0     0     0     0     0     0     0     0     0
4 MARIA       1     1     0     0     0     0     0     0     0     0     0
5 MARIO       1     0     0     0     0     1     0     0     0     0     1
6 MATEO       1     0     1     0     0     0     0     0     0     0     0
7 NICOLAS     1     0     0     0     0     0     0     0     0     0     0

La característica 1 estaba presente en todos. La 4,5, 7, 8, 10 en ninguno. Por tanto solo la 2,3,6,9,11 podrían ser útiles para diferenciar a los actores/características que podrían tener algún valor para saber qué características son más fáciles de descubrir. Tomo nota para cuando nos haga falta e este vector:

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

dfActorItemDiscriminante <- dfActorItem %>% filter(ITEM %in% itemDiscriminante) %>% filter(PRESENTEREAL==1) %>% select(ACTOR,ITEM)
dfActorItemDiscriminante
   ACTOR ITEM
1 ARTURO    9
2  MARIA    2
3  MARIO    6
4  MARIO   11
5  MATEO    3

Claramente no podemos separar el efecto ITEM del efecto ACTOR (salvo el caso de MARIO). Así que será algo que consideramos casi equivalentes.

Ahora me gustaría estudiar los aciertos y errores para cada sujeto e item del grupo 1.

dfLong3=dfLong2 %>%  inner_join(dfActorItem,by = join_by(ACTOR, ITEM)) %>% mutate(itemOK=as.integer(PRESENTE==PRESENTEREAL), itemKO=as.integer(PRESENTE!=PRESENTEREAL))
dfLong3 %>% group_by(ITEM,PRESENTEREAL) %>% summarise(itemOK=sum(itemOK),itemKO=sum(itemKO))
`summarise()` has grouped output by 'ITEM'. You can override using the
`.groups` argument.
# A tibble: 16 × 4
# Groups:   ITEM [11]
    ITEM PRESENTEREAL itemOK itemKO
   <int>        <int>  <int>  <int>
 1     1            1    278    177
 2     2            0    383      7
 3     2            1     63      2
 4     3            0    378     12
 5     3            1     61      4
 6     4            0    376     79
 7     5            0    329    126
 8     6            0    374     16
 9     6            1     57      8
10     7            0    447      8
11     8            0    454      1
12     9            0    389      1
13     9            1     43     22
14    10            0    448      7
15    11            0    347     43
16    11            1     59      6

¿Son todos los ITEM-ACTOR PRESENTE O AUSENTE igual de fácil de detectar?

dfLong4 = dfLong3 %>% mutate(ITEM_PRESENTEREAL=sprintf("%02d-%d",ITEM,PRESENTEREAL),
                   ACIERTO=PRESENTE==PRESENTEREAL)
dfLong4
# A tibble: 5,005 × 12
   SUJETO ACTOR   ITEM PRESENTE GRUPO TRIAJE NOTRIAJE PRESENTEREAL itemOK itemKO
    <dbl> <chr>  <int>    <int> <int>  <int>    <int>        <int>  <int>  <int>
 1      1 ARTURO     1        1     1      1        0            1      1      0
 2      1 ARTURO     2        0     1      1        0            0      1      0
 3      1 ARTURO     3        0     1      1        0            0      1      0
 4      1 ARTURO     4        0     1      1        0            0      1      0
 5      1 ARTURO     5        1     1      1        0            0      0      1
 6      1 ARTURO     6        1     1      1        0            0      0      1
 7      1 ARTURO     7        0     1      1        0            0      1      0
 8      1 ARTURO     8        0     1      1        0            0      1      0
 9      1 ARTURO     9        0     1      1        0            1      0      1
10      1 ARTURO    10        0     1      1        0            0      1      0
# ℹ 4,995 more rows
# ℹ 2 more variables: ITEM_PRESENTEREAL <chr>, ACIERTO <lgl>
dfLong4 %>%
  ggbarstats(y=ITEM_PRESENTEREAL, x=ACIERTO, bf.message = FALSE)

Voy a limitarme ahora solo a los ITEMS que son discriminantes:

dfLong4 %>% inner_join(dfActorItemDiscriminante %>% select(ITEM), by = join_by( ITEM)) %>%  
  select(SUJETO,ACTOR,ITEM_PRESENTEREAL,ACIERTO) %>% arrange(ACTOR,ITEM_PRESENTEREAL) %>% 
  ggbarstats(y=ITEM_PRESENTEREAL, x=ACIERTO, bf.message = FALSE)

La más curiosa es la característica 9. Cuando no está es fácil de acertar con ella. Cuando sí está, la tasa de acierto baja al 66%. Algo similar pasa con la 6, pero menos marcado. En todo lo demás, esté o no la característica presente es igual de fácil acertarla.

Vamos a ver un poco más de detalle:

Para la característica 9:

dfLong4 %>% filter(ITEM==9) %>%  
  select(SUJETO,ACTOR,ITEM_PRESENTEREAL,ACIERTO) %>% arrange(ACTOR,ITEM_PRESENTEREAL) %>% 
  ggbarstats(y=ITEM_PRESENTEREAL, x=ACIERTO, bf.message = FALSE)

Para la característica 6:

dfLong4 %>% filter(ITEM==6) %>%  
  select(SUJETO,ACTOR,ITEM_PRESENTEREAL,ACIERTO) %>% arrange(ACTOR,ITEM_PRESENTEREAL) %>% 
  ggbarstats(y=ITEM_PRESENTEREAL, x=ACIERTO, bf.message = FALSE)

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)

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:

dfCompTriaje  %>% 
  ggbarstats(y=ACTOR, x=DIFERENCIA, bf.message = FALSE)

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:

dfCompTriaje %>% filter(GRUPO==0)  %>% 
  ggbarstats(y=ACTOR, x=DIFERENCIA, bf.message = FALSE,
             title="Grupo 0")

dfCompTriaje %>% filter(GRUPO==1)  %>% 
  ggbarstats(y=ACTOR, x=DIFERENCIA, bf.message = FALSE,
             title="Grupo 1")

Me resultan interesantes algunas diferencias claras a la hora de evaluar a los actores en un grupo y otro. Vamos a centrarnos en las comparaciones, actor a actor:

listaPorACTOR= dfCompTriaje %>% split(.$ACTOR) 


listaGraficos = listaPorACTOR%>% map2(names(listaPorACTOR), ~ {.x %>% ggstatsplot::ggbarstats(y=GRUPO, x=DIFERENCIA,bf.message = FALSE)+ggtitle(.y)})

#Crear con la lista de Gráficos uno solo de dos columnas
listaGraficos
$ARTURO


$JAVIER


$LAURA


$MARIA


$MARIO


$MATEO


$NICOLAS

El único caso que queda donde es GRUPO 1 es escandalosamente peor que el GRUPO 0 es el de ARTURO. En los demás o bien el GRUPO 1 es significativamente mejor que el GRUPO 0, o bien no hay diferencia significativas entre ambos.

listaPorACTOR= dfCompTriaje %>% filter(DIFERENCIA!=0) %>% split(.$ACTOR) 


listaGraficos = listaPorACTOR%>% map2(names(listaPorACTOR), ~ {.x %>% ggstatsplot::ggbarstats(y=GRUPO, x=DIFERENCIA,bf.message = FALSE)+ggtitle(.y)})

#Crear con la lista de Gráficos uno solo de dos columnas
listaGraficos
$ARTURO


$JAVIER


$LAURA


$MARIA


$MARIO


$MATEO


$NICOLAS

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,SUJETO) %>% 
  summarise(PCTACIERTOS=100*sum(DIFERENCIA==0)/sum(!is.na(DIFERENCIA)),
            ERRORMEDIO=mean(abs(DIFERENCIA)),.groups = "drop") 

dfTriajeTotal
# A tibble: 114 × 4
   GRUPO SUJETO PCTACIERTOS ERRORMEDIO
   <int>  <int>       <dbl>      <dbl>
 1     0     66        33.3      1    
 2     0     67        57.1      0.429
 3     0     68        42.9      0.714
 4     0     69        42.9      0.714
 5     0     70        42.9      0.857
 6     0     71        57.1      0.571
 7     0     72        28.6      0.714
 8     0     73        57.1      0.571
 9     0     74        85.7      0.143
10     0     75        28.6      1    
# ℹ 104 more rows

Comparemos ambos grupos en ambas medidas:

dfTriajeTotal %>% 
  ggbetweenstats(x=GRUPO, y=PCTACIERTOS, bf.message = FALSE,
             title="Porcentaje de aciertos")

t.test(PCTACIERTOS ~ GRUPO, data = dfTriajeTotal, var.equal = FALSE, conf.level = 0.95) %>% broom::glance()
# A tibble: 1 × 10
  estimate estimate1 estimate2 statistic p.value parameter conf.low conf.high
     <dbl>     <dbl>     <dbl>     <dbl>   <dbl>     <dbl>    <dbl>     <dbl>
1    -9.24      43.3      52.6     -2.32  0.0224      97.2    -17.1     -1.34
# ℹ 2 more variables: method <chr>, alternative <chr>

The Welch Two Sample t-test, which tested the difference in “Percentage of correct answers” by group (mean in intervention group = 52.56, mean in control group = 43.32), suggests that there is a positive effect from filling out the questionnaire. This effect is statistically significant and of medium magnitude (difference = 9.24, 95% CI [1.34, 17.15], t(97.22) = 2.32, p = .022; Hedge’s g = 0.44, 95% CI [0.06, 0.81]).

dfTriajeTotal %>% 
  ggbetweenstats(x=GRUPO, y=ERRORMEDIO, bf.message = FALSE,
             title="Error medio")

t.test(ERRORMEDIO ~ GRUPO, data = dfTriajeTotal, var.equal = FALSE, conf.level = 0.95) %>% broom::glance()
# A tibble: 1 × 10
  estimate estimate1 estimate2 statistic p.value parameter conf.low conf.high
     <dbl>     <dbl>     <dbl>     <dbl>   <dbl>     <dbl>    <dbl>     <dbl>
1    0.138     0.678     0.540      2.74 0.00726      95.2   0.0381     0.237
# ℹ 2 more variables: method <chr>, alternative <chr>

The Welch Two Sample t-test, which tested the difference in “mean absolute error in triaje” by group (mean in intervention group = 0.54, mean in control group = 0.68), suggests that there is a positive effect from filling out the questionnaire. This effect is statistically significant and of medium magnitude (difference = 0.18, 95% CI [0.04, 0.24], t(95.17) = 2.74, p = .007; Hedge’s g = 0.52, 95% CI [0.14, 0.89]).

Análisis multivariante

El análisis lo podemos hacer usando modelos lineales o modelos multinivel. Vamos a empezar por el lineal que siempre es más fácil de explicar.

Modelo lineal

La base de datos que utilizamos es:

dfLineal= dfTriajeTotal %>% 
  select(GRUPO, SUJETO,PCTACIERTOS,ERRORMEDIO) %>% inner_join(dfTrans %>% select(GRUPO,SUJETO,PROFESION,SEXO,EDAD,TMMS_ATENCION,TMMS_CLARIDAD,TMMS_REGULACION,RESILIENCIA,PSICOLOGIA,TOTALCOMP))
Joining with `by = join_by(GRUPO, SUJETO)`
dfLineal
# A tibble: 114 × 13
   GRUPO     SUJETO PCTACIERTOS ERRORMEDIO PROFESION SEXO     EDAD TMMS_ATENCION
   <dbl+lbl>  <dbl>       <dbl>      <dbl> <dbl+lbl> <dbl+l> <dbl>         <dbl>
 1 0 [SIN C…     66        33.3      1     1 [PSICÓ… 1 [VAR…    66             7
 2 0 [SIN C…     67        57.1      0.429 2 [MÉDIC… 2 [MUJ…    54             8
 3 0 [SIN C…     68        42.9      0.714 1 [PSICÓ… 1 [VAR…    67             8
 4 0 [SIN C…     69        42.9      0.714 2 [MÉDIC… 2 [MUJ…    60            14
 5 0 [SIN C…     70        42.9      0.857 4 [OTROS… 2 [MUJ…    34            20
 6 0 [SIN C…     71        57.1      0.571 4 [OTROS… 2 [MUJ…    57            16
 7 0 [SIN C…     72        28.6      0.714 1 [PSICÓ… 1 [VAR…    61            15
 8 0 [SIN C…     73        57.1      0.571 1 [PSICÓ… 1 [VAR…    76             4
 9 0 [SIN C…     74        85.7      0.143 1 [PSICÓ… 1 [VAR…    49            13
10 0 [SIN C…     75        28.6      1     1 [PSICÓ… 1 [VAR…    45            16
# ℹ 104 more rows
# ℹ 5 more variables: TMMS_CLARIDAD <dbl>, TMMS_REGULACION <dbl>,
#   RESILIENCIA <dbl>, PSICOLOGIA <dbl+lbl>, TOTALCOMP <dbl>
modeloPctAciertos=lm(PCTACIERTOS ~ GRUPO+SEXO+EDAD+TMMS_ATENCION+TMMS_CLARIDAD+TMMS_REGULACION+RESILIENCIA+PSICOLOGIA+TOTALCOMP, data = dfLineal)

summary(modeloPctAciertos)

Call:
lm(formula = PCTACIERTOS ~ GRUPO + SEXO + EDAD + TMMS_ATENCION + 
    TMMS_CLARIDAD + TMMS_REGULACION + RESILIENCIA + PSICOLOGIA + 
    TOTALCOMP, data = dfLineal)

Residuals:
    Min      1Q  Median      3Q     Max 
-49.912 -14.506   0.163  15.971  40.437 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)   
(Intercept)     44.82081   18.99726   2.359  0.02021 * 
GRUPO           10.13937    4.07237   2.490  0.01440 * 
SEXO            -2.35957    4.38358  -0.538  0.59156   
EDAD             0.07838    0.17849   0.439  0.66148   
TMMS_ATENCION    0.83306    0.59696   1.395  0.16590   
TMMS_CLARIDAD    0.41879    0.71000   0.590  0.55660   
TMMS_REGULACION  0.77740    0.65511   1.187  0.23811   
RESILIENCIA     -1.25687    0.43514  -2.888  0.00473 **
PSICOLOGIA       5.38721    4.20513   1.281  0.20306   
TOTALCOMP        0.16615    0.35436   0.469  0.64016   
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 20.45 on 102 degrees of freedom
  (2 observations deleted due to missingness)
Multiple R-squared:  0.1494,    Adjusted R-squared:  0.07436 
F-statistic: 1.991 on 9 and 102 DF,  p-value: 0.04778

Solo lo utilizaría para decir que se mantiene el efecto de la variable principal (incluso mejora) tras ajustar por el resto de variables. Dado que R2 no es una maravilla no me metería en intentar crear una teoría genial para ver como influye el resto de cosas en el triaje. El grupo va sobrado aúnque post-hoc podríamos estudiar un modelo donde solo esté el GRUPO y la resiliencia que es la única variable aparentemente interesante.

Los residuos no tienen mala pinta, así que por mí el modelo no está mal utilizado:

residuals(modeloPctAciertos) %>% hist()

residuals(modeloPctAciertos) %>% qqnorm()

y ahora con pruebas de normalidad de Shapiro-Wilk:

shapiro.test(residuals(modeloPctAciertos))

    Shapiro-Wilk normality test

data:  residuals(modeloPctAciertos)
W = 0.98579, p-value = 0.285

Vamos a hacer lo mismo para la variable ERRORMEDIO:

modeloErrorMedio=lm(ERRORMEDIO ~ GRUPO+SEXO+EDAD+TMMS_ATENCION+TMMS_CLARIDAD+TMMS_REGULACION+RESILIENCIA+PSICOLOGIA+TOTALCOMP, data = dfLineal)
summary(modeloErrorMedio)

Call:
lm(formula = ERRORMEDIO ~ GRUPO + SEXO + EDAD + TMMS_ATENCION + 
    TMMS_CLARIDAD + TMMS_REGULACION + RESILIENCIA + PSICOLOGIA + 
    TOTALCOMP, data = dfLineal)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.51404 -0.19494 -0.01696  0.19174  0.55809 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)   
(Intercept)      0.7457483  0.2368059   3.149  0.00215 **
GRUPO           -0.1532245  0.0507631  -3.018  0.00321 **
SEXO             0.0163033  0.0546425   0.298  0.76603   
EDAD            -0.0003527  0.0022249  -0.159  0.87435   
TMMS_ATENCION   -0.0088059  0.0074413  -1.183  0.23941   
TMMS_CLARIDAD   -0.0048054  0.0088504  -0.543  0.58835   
TMMS_REGULACION -0.0101145  0.0081662  -1.239  0.21834   
RESILIENCIA      0.0158903  0.0054241   2.930  0.00419 **
PSICOLOGIA      -0.0805073  0.0524180  -1.536  0.12767   
TOTALCOMP       -0.0050795  0.0044172  -1.150  0.25286   
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.2549 on 102 degrees of freedom
  (2 observations deleted due to missingness)
Multiple R-squared:  0.1779,    Adjusted R-squared:  0.1054 
F-statistic: 2.453 on 9 and 102 DF,  p-value: 0.01427

De nuevo, sale aún mejor que el modelo univariante. Sobre los residuos, una maravilla:

residuals(modeloErrorMedio) %>% hist()

residuals(modeloErrorMedio) %>% qqnorm()

Y ahora con pruebas de normalidad de Shapiro-Wilk

shapiro.test(residuals(modeloErrorMedio))

    Shapiro-Wilk normality test

data:  residuals(modeloErrorMedio)
W = 0.98886, p-value = 0.49

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(GRUPO,SUJETO,ACTOR,DIFERENCIA) %>% mutate(ACIERTO=as.integer(DIFERENCIA==0))  %>% inner_join(dfTrans %>% select(GRUPO,SUJETO,PROFESION,SEXO,EDAD,TMMS_ATENCION,TMMS_CLARIDAD,TMMS_REGULACION,RESILIENCIA,PSICOLOGIA, TOTALCOMP)) %>% 
  mutate(ACTOR=as.factor(ACTOR))
Joining with `by = join_by(GRUPO, SUJETO)`
dfMultinivel
# A tibble: 819 × 14
   GRUPO   SUJETO ACTOR DIFERENCIA ACIERTO PROFESION SEXO     EDAD TMMS_ATENCION
   <dbl+l>  <dbl> <fct>      <dbl>   <int> <dbl+lbl> <dbl+l> <dbl>         <dbl>
 1 1 [CON…      1 ARTU…         -1       0 2 [MÉDIC… 1 [VAR…    60             8
 2 1 [CON…      1 MARIO         -1       0 2 [MÉDIC… 1 [VAR…    60             8
 3 1 [CON…      1 LAURA          0       1 2 [MÉDIC… 1 [VAR…    60             8
 4 1 [CON…      1 JAVI…          0       1 2 [MÉDIC… 1 [VAR…    60             8
 5 1 [CON…      1 MARIA         -1       0 2 [MÉDIC… 1 [VAR…    60             8
 6 1 [CON…      1 NICO…          0       1 2 [MÉDIC… 1 [VAR…    60             8
 7 1 [CON…      1 MATEO         -2       0 2 [MÉDIC… 1 [VAR…    60             8
 8 1 [CON…      2 ARTU…         -1       0 2 [MÉDIC… 2 [MUJ…    49            16
 9 1 [CON…      2 MARIO         -1       0 2 [MÉDIC… 2 [MUJ…    49            16
10 1 [CON…      2 LAURA          0       1 2 [MÉDIC… 2 [MUJ…    49            16
# ℹ 809 more rows
# ℹ 5 more variables: TMMS_CLARIDAD <dbl>, TMMS_REGULACION <dbl>,
#   RESILIENCIA <dbl>, PSICOLOGIA <dbl+lbl>, TOTALCOMP <dbl>

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

modeloMultinivel=glmer(ACIERTO ~ GRUPO+SEXO+EDAD+TMMS_ATENCION+TMMS_CLARIDAD+TMMS_REGULACION+RESILIENCIA+PSICOLOGIA+TOTALCOMP+(1|ACTOR), data = dfMultinivel, family = binomial(link = "logit"))
Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, :
Model failed to converge with max|grad| = 0.00243674 (tol = 0.002, component 1)
summary(modeloMultinivel)
Generalized linear mixed model fit by maximum likelihood (Laplace
  Approximation) [glmerMod]
 Family: binomial  ( logit )
Formula: ACIERTO ~ GRUPO + SEXO + EDAD + TMMS_ATENCION + TMMS_CLARIDAD +  
    TMMS_REGULACION + RESILIENCIA + PSICOLOGIA + TOTALCOMP +      (1 | ACTOR)
   Data: dfMultinivel

     AIC      BIC   logLik deviance df.resid 
  1047.5   1098.5   -512.8   1025.5      750 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-1.9331 -0.9344 -0.6105  0.9677  1.6244 

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

Fixed effects:
                 Estimate Std. Error z value Pr(>|z|)   
(Intercept)     -0.312940   0.745462  -0.420  0.67464   
GRUPO            0.462664   0.156860   2.950  0.00318 **
SEXO            -0.095900   0.170440  -0.563  0.57366   
EDAD             0.003549   0.006871   0.516  0.60553   
TMMS_ATENCION    0.031003   0.023089   1.343  0.17935   
TMMS_CLARIDAD    0.016761   0.027397   0.612  0.54068   
TMMS_REGULACION  0.029479   0.025259   1.167  0.24319   
RESILIENCIA     -0.048002   0.017221  -2.787  0.00531 **
PSICOLOGIA       0.155804   0.162226   0.960  0.33685   
TOTALCOMP        0.008950   0.013706   0.653  0.51376   
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) GRUPO  SEXO   EDAD   TMMS_A TMMS_C TMMS_R RESILI PSICOL
GRUPO       -0.020                                                        
SEXO        -0.418 -0.096                                                 
EDAD        -0.610 -0.236  0.258                                          
TMMS_ATENCI -0.209  0.085 -0.314  0.244                                   
TMMS_CLARID  0.016 -0.086  0.037 -0.063 -0.289                            
TMMS_REGULA -0.131  0.005  0.119  0.171 -0.008 -0.147                     
RESILIENCIA -0.210  0.052  0.073 -0.087 -0.098 -0.146 -0.459              
PSICOLOGIA   0.117  0.090 -0.005 -0.113  0.093 -0.095  0.053 -0.104       
TOTALCOMP   -0.398  0.000 -0.030  0.062 -0.002 -0.275 -0.068 -0.212 -0.144
optimizer (Nelder_Mead) convergence code: 0 (OK)
Model failed to converge with max|grad| = 0.00243674 (tol = 0.002, component 1)

Los resultados son del mismo tipo, pero ahora la significación es aún mejor. Así que lo dejaría en el modelo lineal y si el revisor pide otra cosa, pues ya sabes que se lo puedes dar y saldrá aún más sólido.

La tabla ahora vendría como estimaciones de ODDS RATIOS para acertar donde solo es de interés la linea de GRUPO y el resto son solo variables de control que no necesitáis ni mostrar.

tidy_model <- broom.mixed::tidy(modeloMultinivel, exponentiate = TRUE, effects = "fixed", conf.int = TRUE, conf.level = 0.95)
tidy_model %>% select(term,estimate,p.value,conf.low,conf.high)
# A tibble: 10 × 5
   term            estimate p.value conf.low conf.high
   <chr>              <dbl>   <dbl>    <dbl>     <dbl>
 1 (Intercept)        0.731 0.675      0.170     3.15 
 2 GRUPO              1.59  0.00318    1.17      2.16 
 3 SEXO               0.909 0.574      0.651     1.27 
 4 EDAD               1.00  0.606      0.990     1.02 
 5 TMMS_ATENCION      1.03  0.179      0.986     1.08 
 6 TMMS_CLARIDAD      1.02  0.541      0.964     1.07 
 7 TMMS_REGULACION    1.03  0.243      0.980     1.08 
 8 RESILIENCIA        0.953 0.00531    0.921     0.986
 9 PSICOLOGIA         1.17  0.337      0.850     1.61 
10 TOTALCOMP          1.01  0.514      0.982     1.04 

After adjusting by SEXO,…PSICOLOGIA, the odds of correctly triaging a patient in the intervention group are 1.63 times higher than in the control group (OR = 1.63, 95% CI [1.2, 2.22], p = .001).

La cuestión de evaluar cómo afecta a un profesional a cuestionar sobre su diagnóstico

La aproximación simple estaría en las pruebas chi-cuadrdo que vimos arriba. Así que si queréis hacerlo de forma más sofisticada, podríamos hacer un modelo multinivel con la variable NOTRIAJE como variable dependiente. El ACTOR seguiría siendo el efecto random y el resto variables de control con efecto fijo:

dfDuda= dfCompTriaje %>% select(GRUPO,SUJETO,ACTOR,NOTRIAJE) %>% inner_join(dfTrans %>% select(GRUPO,SUJETO,PROFESION,SEXO,EDAD,TMMS_ATENCION,TMMS_CLARIDAD,TMMS_REGULACION,RESILIENCIA,PSICOLOGIA, TOTALCOMP)) %>% 
  mutate(ACTOR=as.factor(ACTOR))
Joining with `by = join_by(GRUPO, SUJETO)`
dfDuda
# A tibble: 819 × 13
   GRUPO             SUJETO ACTOR NOTRIAJE PROFESION SEXO     EDAD TMMS_ATENCION
   <dbl+lbl>          <dbl> <fct>    <int> <dbl+lbl> <dbl+l> <dbl>         <dbl>
 1 1 [CON CHECK_LIS…      1 ARTU…        0 2 [MÉDIC… 1 [VAR…    60             8
 2 1 [CON CHECK_LIS…      1 MARIO        0 2 [MÉDIC… 1 [VAR…    60             8
 3 1 [CON CHECK_LIS…      1 LAURA        0 2 [MÉDIC… 1 [VAR…    60             8
 4 1 [CON CHECK_LIS…      1 JAVI…        0 2 [MÉDIC… 1 [VAR…    60             8
 5 1 [CON CHECK_LIS…      1 MARIA        0 2 [MÉDIC… 1 [VAR…    60             8
 6 1 [CON CHECK_LIS…      1 NICO…        0 2 [MÉDIC… 1 [VAR…    60             8
 7 1 [CON CHECK_LIS…      1 MATEO        0 2 [MÉDIC… 1 [VAR…    60             8
 8 1 [CON CHECK_LIS…      2 ARTU…        0 2 [MÉDIC… 2 [MUJ…    49            16
 9 1 [CON CHECK_LIS…      2 MARIO        0 2 [MÉDIC… 2 [MUJ…    49            16
10 1 [CON CHECK_LIS…      2 LAURA        0 2 [MÉDIC… 2 [MUJ…    49            16
# ℹ 809 more rows
# ℹ 5 more variables: TMMS_CLARIDAD <dbl>, TMMS_REGULACION <dbl>,
#   RESILIENCIA <dbl>, PSICOLOGIA <dbl+lbl>, TOTALCOMP <dbl>

Empezamos con el modelo multinivel más simple:

modeloMultinivel2=glmer(NOTRIAJE ~ GRUPO+(1|ACTOR), data = dfDuda, family = binomial(link = "logit"))
boundary (singular) fit: see help('isSingular')
summary(modeloMultinivel2)
Generalized linear mixed model fit by maximum likelihood (Laplace
  Approximation) [glmerMod]
 Family: binomial  ( logit )
Formula: NOTRIAJE ~ GRUPO + (1 | ACTOR)
   Data: dfDuda

     AIC      BIC   logLik deviance df.resid 
   310.9    325.1   -152.5    304.9      816 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-0.3189 -0.3189 -0.3189 -0.0743 13.4536 

Random effects:
 Groups Name        Variance Std.Dev.
 ACTOR  (Intercept) 0        0       
Number of obs: 819, groups:  ACTOR, 7

Fixed effects:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept)  -5.1985     0.7090  -7.332 2.26e-13 ***
GRUPO         2.9127     0.7272   4.005 6.20e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
      (Intr)
GRUPO -0.975
optimizer (Nelder_Mead) convergence code: 0 (OK)
boundary (singular) fit: see help('isSingular')

Confirmadísimo lo que vimos en modo de gráfico con pruebas chi-cuadrado. Si lo redactamos en forma de ODDS RATIOS, no puede quedar más claro:

tidy_model <- broom.mixed::tidy(modeloMultinivel2, exponentiate = TRUE, effects = "fixed", conf.int = TRUE, conf.level = 0.95)
tidy_model %>% select(term,estimate,p.value,conf.low,conf.high)
# A tibble: 2 × 5
  term        estimate  p.value conf.low conf.high
  <chr>          <dbl>    <dbl>    <dbl>     <dbl>
1 (Intercept)  0.00552 2.26e-13  0.00138    0.0222
2 GRUPO       18.4     6.20e- 5  4.43      76.6   

Ahora ajustamos el modelo por el resto de variables de control:

modeloMultinivel3=glmer(NOTRIAJE ~ GRUPO+SEXO+EDAD+TMMS_ATENCION+TMMS_CLARIDAD+TMMS_REGULACION+RESILIENCIA+PSICOLOGIA+TOTALCOMP+(1|ACTOR), data = dfDuda, family = binomial(link = "logit"))
boundary (singular) fit: see help('isSingular')
summary(modeloMultinivel3)
Generalized linear mixed model fit by maximum likelihood (Laplace
  Approximation) [glmerMod]
 Family: binomial  ( logit )
Formula: NOTRIAJE ~ GRUPO + SEXO + EDAD + TMMS_ATENCION + TMMS_CLARIDAD +  
    TMMS_REGULACION + RESILIENCIA + PSICOLOGIA + TOTALCOMP +      (1 | ACTOR)
   Data: dfDuda

     AIC      BIC   logLik deviance df.resid 
   300.5    352.1   -139.2    278.5      794 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-0.6009 -0.2669 -0.1314 -0.0605 15.5069 

Random effects:
 Groups Name        Variance  Std.Dev. 
 ACTOR  (Intercept) 6.722e-16 2.593e-08
Number of obs: 805, groups:  ACTOR, 7

Fixed effects:
                 Estimate Std. Error z value Pr(>|z|)    
(Intercept)     -6.982207   1.924431  -3.628 0.000285 ***
GRUPO            2.797572   0.739917   3.781 0.000156 ***
SEXO             1.007049   0.435963   2.310 0.020891 *  
EDAD             0.017078   0.016324   1.046 0.295478    
TMMS_ATENCION    0.063177   0.051858   1.218 0.223122    
TMMS_CLARIDAD   -0.095585   0.063641  -1.502 0.133109    
TMMS_REGULACION -0.087366   0.059498  -1.468 0.142000    
RESILIENCIA      0.025824   0.038979   0.663 0.507641    
PSICOLOGIA       0.981229   0.357185   2.747 0.006012 ** 
TOTALCOMP       -0.007835   0.030132  -0.260 0.794850    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) GRUPO  SEXO   EDAD   TMMS_A TMMS_C TMMS_R RESILI PSICOL
GRUPO       -0.286                                                        
SEXO        -0.528 -0.070                                                 
EDAD        -0.687 -0.080  0.389                                          
TMMS_ATENCI -0.097  0.047 -0.210  0.050                                   
TMMS_CLARID  0.135 -0.052 -0.135 -0.193 -0.355                            
TMMS_REGULA -0.163  0.015  0.291  0.262 -0.236 -0.160                     
RESILIENCIA -0.253  0.055  0.011  0.071  0.037 -0.228 -0.416              
PSICOLOGIA   0.006  0.055 -0.028  0.119 -0.017 -0.143  0.055  0.092       
TOTALCOMP   -0.355 -0.093  0.035  0.108 -0.004 -0.128 -0.062 -0.269 -0.287
optimizer (Nelder_Mead) convergence code: 0 (OK)
boundary (singular) fit: see help('isSingular')

EN este CASO el SEXO=1 es un factor que hace dudar y también el saber de PSICOLOGÏA.

tidy_model <- broom.mixed::tidy(modeloMultinivel3, exponentiate = TRUE, effects = "fixed", conf.int = TRUE, conf.level = 0.95)
tidy_model %>% select(term,estimate,p.value,conf.low,conf.high)
# A tibble: 10 × 5
   term             estimate  p.value  conf.low conf.high
   <chr>               <dbl>    <dbl>     <dbl>     <dbl>
 1 (Intercept)      0.000928 0.000285 0.0000214    0.0403
 2 GRUPO           16.4      0.000156 3.85        70.0   
 3 SEXO             2.74     0.0209   1.16         6.43  
 4 EDAD             1.02     0.295    0.985        1.05  
 5 TMMS_ATENCION    1.07     0.223    0.962        1.18  
 6 TMMS_CLARIDAD    0.909    0.133    0.802        1.03  
 7 TMMS_REGULACION  0.916    0.142    0.815        1.03  
 8 RESILIENCIA      1.03     0.508    0.951        1.11  
 9 PSICOLOGIA       2.67     0.00601  1.32         5.37  
10 TOTALCOMP        0.992    0.795    0.935        1.05