1. Introducción y Carga de Librerías

Para este análisis, utilizaremos las librerías estándar del tidyverse para manipulación y visualización, y knitr para la presentación de tablas.

library(tidyverse)
library(knitr)

2. Carga de Datos

Los datos provienen de un experimento para comparar los costos mensuales de cuatro compañías de telefonía celular (A, B, C, D), controlando por tres niveles de uso (Bajo, Medio, Alto).

Ingresamos los datos manualmente basados en la tabla proporcionada:

# Definimos los vectores de datos
costos <- c(27, 24, 31, 23,     # Nivel Bajo
            68, 76, 65, 67,     # Nivel Medio
            308, 326, 312, 300) # Nivel Alto

# Creamos los factores correspondientes
# Nivel de Uso: Repetimos cada nivel 4 veces (porque hay 4 compañías por nivel)
nivel_uso <- factor(rep(c("Bajo", "Medio", "Alto"), each = 4), 
                    levels = c("Bajo", "Medio", "Alto"))

# Compañía: Repetimos la secuencia A,B,C,D 3 veces (una vez por cada nivel)
compania <- factor(rep(c("A", "B", "C", "D"), 3))

# Creamos el DataFrame
datos_telefonia <- data.frame(
  Nivel_Uso = nivel_uso,
  Compania = compania,
  Costo = costos
)

# Mostramos la tabla en formato lista (formato "tidy")
kable(head(datos_telefonia), caption = "Primeras filas de los datos crudos")
Primeras filas de los datos crudos
Nivel_Uso Compania Costo
Bajo A 27
Bajo B 24
Bajo C 31
Bajo D 23
Medio A 68
Medio B 76

3. Análisis Descriptivo

3.1 Verificación de Totales (Replicando la tabla original)

Para asegurarnos de que nuestros datos coinciden perfectamente con los del ejercicio, generamos una tabla cruzada que muestra la suma de costos por Compañía y Nivel de Uso, incluyendo los totales marginales (\(B_i\), \(T_j\) y \(G\))

# Creamos una tabla cruzada sumando los costos
tabla_cruzada <- xtabs(Costo ~ Nivel_Uso + Compania, data = datos_telefonia)

# Agregamos los márgenes (totales por fila y columna)
tabla_con_totales <- addmargins(tabla_cruzada)

# Mostramos la tabla
print(tabla_con_totales)
##          Compania
## Nivel_Uso    A    B    C    D  Sum
##     Bajo    27   24   31   23  105
##     Medio   68   76   65   67  276
##     Alto   308  326  312  300 1246
##     Sum    403  426  408  390 1627

Nota: Podemos verificar que el Gran Total (\(G\)) es 1627, y los totales por columna (\(A=403, B=426\), etc.) coinciden con la imagen del problema.

3.2 Estadísticas Resumen (Promedios y Desviación)

Calculamos las estadísticas resumen (media, desviación estándar) para entender la tendencia central y la dispersión de nuestros grupos.

# Agrupamos por Nivel de Uso (el bloque)
resumen_uso <- datos_telefonia %>%
  group_by(Nivel_Uso) %>%
  summarise(
    Promedio = mean(Costo),
    Desviacion_estandar = sd(Costo),
    n = n()
  )

kable(resumen_uso, caption = "Resumen por Nivel de Uso")
Resumen por Nivel de Uso
Nivel_Uso Promedio Desviacion_estandar n
Bajo 26.25 3.593976 4
Medio 69.00 4.830459 4
Alto 311.50 10.878113 4
# Agrupamos por Compañía (el tratamiento)
resumen_compania <- datos_telefonia %>%
  group_by(Compania) %>%
  summarise(
    Promedio = mean(Costo),
    Desviacion_estandar = sd(Costo),
    n = n()
  )

kable(resumen_compania, caption = "Resumen por Compañía")
Resumen por Compañía
Compania Promedio Desviacion_estandar n
A 134.3333 151.7904 3
B 142.0000 161.4559 3
C 136.0000 153.3656 3
D 130.0000 148.8590 3

4. Análisis Exploratorio Visual

Utilizamos diagramas de caja (boxplots) para visualizar las diferencias, siguiendo el estilo visto en clase.

# Gráfico de cajas por Compañía
ggplot(datos_telefonia, aes(x = Compania, y = Costo, fill = Compania)) +
  geom_boxplot(position = position_dodge(0.8), alpha = 0.7) +
  labs(title = "Comparación de Costos por Compañía",
       subtitle = "Distribución general sin separar por nivel",
       x = "Compañía",
       y = "Costo Mensual ($)") +
  coord_flip() + # Volteamos para mejor legibilidad como en el ejemplo
  theme_minimal()

# Gráfico de cajas por Nivel de Uso
ggplot(datos_telefonia, aes(x = Nivel_Uso, y = Costo, fill = Nivel_Uso)) +
  geom_boxplot(position = position_dodge(0.8), alpha = 0.7) +
  labs(title = "Comparación de Costos por Nivel de Uso",
       subtitle = "Efecto de los bloques",
       x = "Nivel de Uso",
       y = "Costo Mensual ($)") +
  theme_minimal()

# Gráfico de líneas para visualizar posibles interacciones
ggplot(datos_telefonia, aes(x = Compania, y = Costo, group = Nivel_Uso, color = Nivel_Uso)) +
  geom_line(size = 1) +
  geom_point(size = 3) +
  labs(title = "Perfil de Costos: Interacción Compañía - Nivel de Uso",
       x = "Compañía",
       y = "Costo ($)") +
  theme_minimal()

Observación: Las líneas son casi perfectamente paralelas, lo que visualmente sugiere que no hay interacción significativa entre la compañía y el nivel de uso. El efecto del nivel de uso es constante sin importar la compañía.

5. Tabla de Análisis de Varianza (ANOVA)

Realizamos un ANOVA de dos factores.

Nota Técnica sobre la Interacción

En clase vimos modelos con interacción (y ~ A * B). Sin embargo, en este experimento específico, solo tenemos una observación por cada combinación de Compañía y Nivel de Uso (no hay réplicas dentro de las celdas). Matemáticamente, esto impide calcular la interacción (los grados de libertad del error serían cero). Por lo tanto, utilizamos el modelo aditivo (y ~ A + B), que asume que no hay interacción, tal como lo indica la instrucción de la tarea (“sin interacciones”).

# Modelo Aditivo: Costo ~ Factor1 + Factor2
modelo_anova <- aov(Costo ~ Compania + Nivel_Uso, data = datos_telefonia)

# Mostramos la tabla resumen del ANOVA
summary(modelo_anova)
##             Df Sum Sq Mean Sq  F value   Pr(>F)    
## Compania     3    222      74    1.841     0.24    
## Nivel_Uso    2 189335   94668 2351.990 2.07e-09 ***
## Residuals    6    242      40                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

6. Verificación de Supuestos del Modelo

Para que las conclusiones del ANOVA sean válidas, debemos verificar que los residuos del modelo cumplan con los supuestos de normalidad y homocedasticidad (varianza constante).

# Extraemos los residuos y valores predichos del modelo
datos_telefonia$residuos <- residuals(modelo_anova)
datos_telefonia$predichos <- fitted(modelo_anova)

# 1. Prueba de Normalidad (Shapiro-Wilk)
# H0: Los residuos siguen una distribución normal
shapiro_test <- shapiro.test(datos_telefonia$residuos)
print(shapiro_test)
## 
##  Shapiro-Wilk normality test
## 
## data:  datos_telefonia$residuos
## W = 0.97822, p-value = 0.9756
# Gráfico Q-Q para inspección visual de normalidad
ggplot(datos_telefonia, aes(sample = residuos)) +
  stat_qq() + stat_qq_line(color = "red") +
  labs(title = "Q-Q Plot de Normalidad de Residuos",
       subtitle = "Los puntos deben seguir la línea roja") +
  theme_minimal()

# 2. Homocedasticidad (Residuos vs Predichos)
# Buscamos una distribución aleatoria sin patrones (como embudos)
ggplot(datos_telefonia, aes(x = predichos, y = residuos)) +
  geom_point(size = 3, color = "blue", alpha = 0.6) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
  labs(title = "Residuos vs Valores Predichos",
       subtitle = "Verificación de Homocedasticidad",
       x = "Valores Predichos",
       y = "Residuos") +
  theme_minimal()

Interpretación de Supuestos:

  • Normalidad: Si el valor \(p\) de Shapiro-Wilk es > 0.05 y los puntos en el Q-Q Plot se ajustan a la línea, asumimos normalidad.

  • Homocedasticidad: Si el gráfico de residuos no muestra patrones claros (como una forma de cono), asumimos varianza constante.

7. Interpretación de Resultados

Interpretamos los resultados con un nivel de confianza del 95% (\(\alpha = 0.05\)).

A. Efecto de las Compañías (Tratamientos)

  • Hipótesis (\(H_0\)): \(\mu_A = \mu_B = \mu_C = \mu_D\).

  • Valor p: 0.364

  • Conclusión: Como \(p > 0.05\), no rechazamos \(H_0\). No hay evidencia de diferencias significativas en los costos promedio entre las compañías.

B. Efecto del Nivel de Uso (Bloques)

  • Hipótesis (\(H_0\)): Las medias de los niveles de uso son iguales.

  • Valor p: \(< 2 \times 10^{-16}\) (Significativo ***)

  • Conclusión: Como \(p < 0.05\), rechazamos \(H_0\). El nivel de uso afecta significativamente el costo.

8. Pruebas Post-hoc (Tukey)

Dado que el ANOVA mostró diferencias significativas para el factor Nivel de Uso, realizamos la prueba de Tukey para ver exactamente qué niveles difieren entre sí.

# Aplicamos TukeyHSD al modelo
tukey_resultado <- TukeyHSD(modelo_anova, which = "Nivel_Uso")

# Mostramos los resultados
print(tukey_resultado)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = Costo ~ Compania + Nivel_Uso, data = datos_telefonia)
## 
## $Nivel_Uso
##              diff       lwr       upr     p adj
## Medio-Bajo  42.75  28.98545  56.51455 0.0001875
## Alto-Bajo  285.25 271.48545 299.01455 0.0000000
## Alto-Medio 242.50 228.73545 256.26455 0.0000000
# Visualizamos los intervalos de confianza de las diferencias
plot(tukey_resultado, las=1)

Interpretación de Tukey: Todas las comparaciones entre niveles (Medio-Bajo, Alto-Bajo, Alto-Medio) muestran diferencias significativas (p adj = 0), confirmando que cada salto en el nivel de uso incrementa el costo de manera estadísticamente distinguible.