Apunte 16 — Drivers, importancia relativa y visualización de encuestas

Analítica de Personas · Semestre otoño 2026 · Semana 6 · Prof. René Gempp

1. Drivers de engagement: el problema del VP

Hasta ahora, en esta semana, hemos hecho lo siguiente:

  1. Analizamos la confiabilidad de las cinco sub-escalas de la encuesta con psych::alpha() (Apunte 14).
  2. Confirmamos la estructura factorial con psych::fa() (Apunte 15).
  3. Construimos puntajes promedio para liderazgo, desarrollo, reconocimiento, carga y propósito.

Ahora viene la pregunta del VP de Personas: ¿qué dimensión está moviendo más al engagement global? Esa es la pregunta que decide dónde poner presupuesto.

La herramienta natural es la regresión múltiple con engagement global como VD y las cinco dimensiones como predictores:

modelo <- lm(engagement_global ~ liderazgo + desarrollo +
                                  reconocimiento + carga + proposito,
             data = datos)

summary(modelo)
broom::tidy(modelo, conf.int = TRUE)
Re-uso de la Clase 5 Esta es exactamente la misma sintaxis de lm() que aprendimos en la auditoría salarial. La diferencia: la VD (engagement_global) es continua y no se transforma con logaritmo. Si necesitas refrescar la lectura del summary() y de broom::tidy(), vuelve al Apunte 11.

2. Por qué los coeficientes no responden la pregunta

Lee con cuidado el coeficiente de "liderazgo" en el output:

           term  estimate std.error statistic  p.value conf.low conf.high
1   (Intercept)     0.971     0.273     3.560 0.000391    0.435     1.508
2     liderazgo     0.756     0.063    11.984 0.000000    0.632     0.880
3    desarrollo     0.685     0.067    10.193 0.000000    0.553     0.817
4 reconocimiento    0.429     0.064     6.713 0.000000    0.304     0.555
5         carga    -0.396     0.054    -7.290 0.000000   -0.503    -0.290
6     proposito     0.325     0.062     5.265 0.000000    0.204     0.447

Lectura ingenua: "liderazgo es el driver más fuerte porque tiene el coeficiente más grande". Esa lectura es engañosa, por dos razones:

  1. Los predictores están en distintas unidades. Si liderazgo y desarrollo se miden en la misma escala 1–5 (como aquí), comparar coeficientes es razonable. Pero si midiéramos antigüedad en años y otros predictores en escalas Likert, los coeficientes serían incomparables.
  2. Los predictores están correlacionados entre sí. Liderazgo y desarrollo tienen correlación ~0,40 en estos datos. Cuando los predictores se solapan, el coeficiente de regresión refleja solo el "efecto único" de cada uno —la parte que no comparte con los demás. Eso no es lo mismo que "qué tanto importa".

Necesitamos otra métrica: la importancia relativa.

3. Importancia relativa: la intuición

La importancia relativa busca responder: "si tuviera que repartir el R² total entre los predictores, ¿qué porcentaje le tocaría a cada uno?". Hay varios métodos para calcularla; el más usado y mejor comportado es el método LMG (Lindeman, Merenda & Gold, 1980), implementado en el paquete relaimpo.

La intuición del LMG: cuando los predictores están correlacionados, el R² que aporta cada uno depende del orden en que entran al modelo. Por ejemplo:

El método LMG resuelve este problema promediando la contribución de cada predictor sobre todos los órdenes posibles de entrada. El resultado es un número por cada predictor, y la suma de los números es el R² total del modelo. Esos números se pueden comparar honestamente como "qué tanto importa cada driver".

Las matemáticas, en una línea LMG es matemáticamente equivalente al "valor de Shapley" de la teoría de juegos cooperativos (Shapley, 1953), aplicado al juego de "repartir el R² entre los jugadores predictores". Para una discusión rigurosa: Grömping, U. (2006). Relative importance for linear regression in R: The package relaimpo. Journal of Statistical Software, 17(1), 1–27.

4. relaimpo::calc.relimp(): cálculo en R

# Instalar (una sola vez)
install.packages("relaimpo")

library(relaimpo)

# Calcular importancia relativa con el método LMG
importancia <- relaimpo::calc.relimp(modelo,
                                       type = "lmg",
                                       rela = TRUE)
importancia
Response variable: engagement_global
Total response variance: 4.21
Analysis based on 936 observations

5 Regressors:
liderazgo desarrollo reconocimiento carga proposito
Proportion of variance explained by model: 64.6%
Metrics are normalized to sum to 100%.

Relative importance metrics:

                     lmg
liderazgo       0.302
desarrollo      0.246
reconocimiento  0.165
carga           0.154
proposito       0.133

Lectura:

El gráfico es un complemento natural:

plot(importancia)

...que produce un gráfico de barras de las contribuciones LMG, ordenadas o no según prefieras.

5. Limitaciones de la importancia relativa

Tres advertencias importantes que conviene tener presentes:

  1. Importancia relativa no es causalidad. Que liderazgo "explique" un 30 % del R² no significa que mejorar liderazgo en X puntos vaya a subir engagement en Y. Para inferencias causales serias se necesitan diseños cuasi-experimentales o experimentos de campo. Reportar la importancia relativa como un argumento para invertir en liderazgo es razonable; reportarla como una garantía de retorno es incorrecto.
  2. Es sensible al conjunto de predictores incluidos. Si quitas un predictor importante del modelo, las contribuciones de los demás se reorganizan. La importancia relativa no es una propiedad "absoluta" del predictor, sino una propiedad de su contribución dentro del modelo que ajustaste.
  3. Varianza explicada no es lo mismo que impacto en valores extremos. Un driver puede explicar mucha varianza pero ser poco accionable; otro puede explicar poca varianza pero ser fácil de mover. La conversación con el VP debe combinar importancia relativa con costo/factibilidad de las palancas.

6. eNPS: cálculo y crítica

El employee Net Promoter Score (eNPS) es la versión organizacional del NPS de Reichheld (2003). La pregunta canónica es:

"En una escala de 0 a 10, ¿qué tan probable es que recomiendes a InnovaCo como un buen lugar para trabajar?"

Las respuestas se categorizan en tres grupos:

RangoCategoría
9 – 10Promotor
7 – 8Pasivo
0 – 6Detractor

Y la fórmula del eNPS es simplemente:

eNPS = % Promotores − % Detractores

El score teórico va de −100 (todos detractores) a +100 (todos promotores).

6.1 Cálculo en R

datos <- datos |>
  mutate(categoria_enps = case_when(
    enps >= 9 ~ "Promotor",
    enps >= 7 ~ "Pasivo",
    TRUE      ~ "Detractor"
  ))

# eNPS global
datos |>
  count(categoria_enps) |>
  mutate(pct = n / sum(n) * 100) |>
  summarise(eNPS = pct[categoria_enps == "Promotor"] -
                       pct[categoria_enps == "Detractor"])

# eNPS segmentado por departamento
datos |>
  group_by(departamento) |>
  summarise(
    promotor = mean(categoria_enps == "Promotor") * 100,
    detractor= mean(categoria_enps == "Detractor") * 100,
    eNPS     = promotor - detractor
  ) |>
  arrange(eNPS)

6.2 Por qué a las empresas les gusta y a los académicos les molesta

A favor

En contra

Recomendación profesional Reporta el eNPS porque tu VP lo va a pedir. Pero acompáñalo del promedio simple del ítem 0–10 y, si el espacio lo permite, de la distribución completa. La transparencia sobre las limitaciones de la métrica es parte de tu credibilidad como analista.

7. Visualización 1: heatmaps con geom_tile()

Cuando quieres mostrar una métrica (engagement promedio) cruzada entre dos categorías (departamento × dimensión), un heatmap permite ver patrones de un vistazo. La función ggplot2 es geom_tile():

# Datos en formato largo
heatmap_data <- datos |>
  group_by(departamento) |>
  summarise(across(c(liderazgo, desarrollo, reconocimiento,
                       carga, proposito), mean)) |>
  pivot_longer(-departamento, names_to = "dimension",
                                values_to = "puntaje")

ggplot(heatmap_data, aes(dimension, departamento, fill = puntaje)) +
  geom_tile(color = "white", linewidth = 0.6) +
  geom_text(aes(label = round(puntaje, 1)),
            color = "white", size = 3.5) +
  scale_fill_gradient2(
    midpoint = 3, low = "#B85042", mid = "#E7E8D1", high = "#0D9488",
    limits = c(1, 5)
  ) +
  labs(title = "Engagement promedio por departamento y dimensión",
       subtitle = "Encuesta InnovaCo 2026 · n = 936",
       x = NULL, y = NULL, fill = "Promedio (1–5)") +
  theme_minimal()
El detalle clave: scale_fill_gradient2() con midpoint anclado Para datos centrados en un valor con significado (e.g., el "neutral" de una escala Likert 1–5 está en 3), usa scale_fill_gradient2(), no scale_fill_gradient(). La paleta divergente (un color para "bajo", otro para "alto", pasando por un color neutral en el punto medio) hace inmediatamente legible qué celdas están "en zona roja" y cuáles "en zona verde". Si usaras una paleta secuencial, todo se vería en un mismo gradiente y perderías la información ordinal del punto medio.

8. Visualización 2: barras divergentes para datos Likert

Las barras divergentes (diverging stacked bar charts) son la forma más honesta de visualizar una distribución de respuestas Likert. La idea: poner el "neutral" en el centro y dejar crecer las respuestas positivas a la derecha y las negativas a la izquierda. Inventadas por Heiberger y Robbins (2014) y popularizadas en R por los paquetes HH y likert.

El patrón en ggplot2 puro:

# Calcular % en cada categoría de respuesta para un ítem
item_div <- datos |>
  count(item_rec_01) |>
  mutate(
    pct = n / sum(n) * 100,
    label = factor(item_rec_01,
                   levels = 1:5,
                   labels = c("Muy en desacuerdo", "En desacuerdo",
                              "Neutral", "De acuerdo", "Muy de acuerdo")),
    pct_signed = case_when(
      item_rec_01 %in% 1:2 ~ -pct,
      item_rec_01 == 3     ~ -pct/2,
      item_rec_01 %in% 4:5 ~ pct
    )
  )

ggplot(item_div, aes(x = pct_signed, y = "item", fill = label)) +
  geom_col() +
  geom_vline(xintercept = 0, color = "black") +
  scale_fill_manual(values = c(
    "Muy en desacuerdo" = "#B85042",
    "En desacuerdo"     = "#D88471",
    "Neutral"           = "#E7E8D1",
    "De acuerdo"        = "#7DAEA0",
    "Muy de acuerdo"    = "#0D9488"
  )) +
  labs(title = "'Mi jefatura reconoce mi trabajo cuando lo hago bien'",
       x = "% de respondientes", y = NULL) +
  theme_minimal()
Una alternativa elegante: el paquete likert Si vas a hacer muchas visualizaciones de este tipo, vale la pena explorar el paquete likert, que automatiza todo el trabajo de barras divergentes con una sintaxis específica para ítems Likert. install.packages("likert") y luego likert::likert(items_df) |> plot().

9. Visualización 3: comparación año a año

Mostrar una caída de engagement de un año al otro requiere una visualización que contextualice la magnitud, no solo que la dramatice. Dos opciones efectivas:

9.1 Dumbbell plot con geom_segment() + geom_point()

comparacion <- datos |>
  group_by(departamento) |>
  summarise(engagement_2026 = mean(engagement_global)) |>
  left_join(hist_2025 |>
              select(departamento,
                     engagement_2025 = engagement_global_2025),
            by = "departamento")

ggplot(comparacion, aes(y = reorder(departamento, engagement_2026))) +
  geom_segment(aes(x = engagement_2025, xend = engagement_2026,
                   yend = departamento),
               linewidth = 1.5, color = "grey60",
               arrow = arrow(length = unit(0.18, "cm"),
                             type = "closed")) +
  geom_point(aes(x = engagement_2025), color = "#A7BEAE", size = 4) +
  geom_point(aes(x = engagement_2026), color = "#B85042", size = 4) +
  labs(title = "Engagement global por departamento: 2025 vs. 2026",
       x = "Engagement promedio (escala 0–10)", y = NULL) +
  theme_minimal()

9.2 Atajo: geom_dumbbell() del paquete ggalt

library(ggalt)

ggplot(comparacion, aes(y = reorder(departamento, engagement_2026),
                         x = engagement_2025, xend = engagement_2026)) +
  geom_dumbbell(colour_x = "#A7BEAE",
                colour_xend = "#B85042",
                size_x = 4, size_xend = 4)

10. Tres principios de visualización para datos de encuesta

  1. Las tablas son para leer; los heatmaps son para ver patrones. Una tabla de 6 departamentos × 5 dimensiones tiene 30 celdas. Un heatmap permite captar el patrón en 2 segundos; una tabla requiere lectura secuencial.
  2. Para datos Likert, las barras divergentes son más honestas que las apiladas. Una barra apilada tradicional alinea todas las respuestas de izquierda a derecha y obliga al ojo a comparar áreas; las divergentes anclan el "neutral" en el centro y hacen inmediato el balance positivo/negativo.
  3. Comparaciones año a año necesitan contexto, no solo flechas. Una caída de 8 puntos sin contexto invita al pánico. Mostrar la serie histórica completa, o el rango intercuartílico de empresas comparables del benchmark, enmarca la magnitud del cambio.

11. Resumen del kit técnico de la semana

FunciónPaquetePara qué sirve
relaimpo::calc.relimp()relaimpoImportancia relativa por método LMG
case_when()dplyrCategorización de respondientes para eNPS
geom_tile()ggplot2Heatmaps de métrica × dos categorías
scale_fill_gradient2()ggplot2Paleta divergente con punto medio anclado
geom_segment() / geom_dumbbell()ggplot2 / ggaltComparación entre dos puntos en el tiempo
likert::likert()likertAtajo para barras divergentes Likert (opcional)