Este documento muestra cómo ejecutar tres pruebas con datos de mercadeo y cómo reportarlas definición, qué mide, supuestos, hipótesis (H0/H1), decisión y conclusión de negocio.
set.seed(7)
# Paquetes (instala si falta)
need <- c("tidyverse","car","emmeans")
has <- need %in% rownames(installed.packages())
if(any(!has)) install.packages(need[!has], dependencies = TRUE)
library(tidyverse) # dplyr, ggplot2, etc.
library(car) # leveneTest, durbinWatsonTest
library(emmeans) # post hoc Scheffé
Qué es: Prueba paramétrica sobre la media de
las diferencias emparejadas (misma unidad medida dos
veces).
Qué mide: Si el cambio medio es
distinto de 0.
Cuándo usar: Diseños antes–después o
A–B en los mismos sujetos; DV en
intervalo/razón.
Supuestos: Diferencias ~ normales;
emparejamiento correcto; independencia entre unidades (entre
sujetos).
Evaluamos el efecto de un nuevo video demo sobre la intención de compra de un servicio digital de Jav5Studio. Se usa un diseño antes–después en la misma muestra: 30 leads calificados responden la misma escala Likert de 7 puntos (1 = “Nada dispuesto a comprar”, 7 = “Totalmente dispuesto a comprar”) antes de ver el video y después de verlo una vez, en la misma sesión. Objetivo gerencial: comprobar si el activo creativo aumenta la predisposición de compra.
Si p < 0,05 y el IC95% del cambio medio > 0 → el video incrementa significativamente la intención. Reporte: t(gl), p, IC95% del cambio, tamaño de efecto (d₍z₎) y implicación de negocio (p. ej., “escalar en retargeting y PDP”).
n <- 30
antes <- round(rnorm(n, mean = 4.2, sd = 0.9), 2)
despues <- round(antes + rnorm(n, mean = 0.5, sd = 0.6), 2)
df_paired <- tibble(id = 1:n, antes, despues) |>
mutate(dif = despues - antes)
df_paired %>% summarise(n=n(), media_dif=mean(dif), sd_dif=sd(dif))
## # A tibble: 1 × 3
## n media_dif sd_dif
## <int> <dbl> <dbl>
## 1 30 0.522 0.478
ggplot(df_paired, aes(x = dif)) +
geom_histogram(bins = 8) +
geom_vline(xintercept = 0, linetype = "dashed") +
labs(title = "Distribución de la diferencia (Después − Antes)")
shapiro.test(df_paired$dif)
##
## Shapiro-Wilk normality test
##
## data: df_paired$dif
## W = 0.99378, p-value = 0.9996
Normalidad de la diferencia (Shapiro–Wilk). El test
aplicado a df_paired$dif
arrojó W =
0.99378 y p = 0.9996. Dado que p ≫
0.05, no rechazamos la hipótesis nula de normalidad:
los datos de la diferencia post–pre son compatibles con
una distribución normal. Esto respalda el supuesto
clave para usar la t de muestras pareadas
según Malhotra. Aun así, recuerda que con muestras pequeñas/medianas la
evidencia gráfica (histograma y QQ-plot) complementa la prueba; si ambos
coinciden con esta conclusión, puedes proceder con la t pareada y
reportar que el supuesto de normalidad de las diferencias se
cumple en esta muestra.
# t pareadas: prueba si el cambio medio (después - antes) es distinto de 0
res_t <- t.test(df_paired$despues, df_paired$antes, paired = TRUE)
res_t # imprime t, gl, p, IC95%, media de la diferencia, etc.
##
## Paired t-test
##
## data: df_paired$despues and df_paired$antes
## t = 5.9714, df = 29, p-value = 1.723e-06
## alternative hypothesis: true mean difference is not equal to 0
## 95 percent confidence interval:
## 0.3429930 0.7003403
## sample estimates:
## mean difference
## 0.5216667
# Tamaño de efecto para datos pareados (Cohen's d_z):
# d_z = media de la diferencia / desviación estándar de la diferencia
media_d <- mean(df_paired$dif) # cambio medio observado
sd_d <- sd(df_paired$dif) # variabilidad del cambio entre sujetos
dz <- media_d / sd_d # magnitud del efecto en unidades de SD
dz # interpreta: ~0.2 pequeño, ~0.5 mediano, ~0.8 grande
## [1] 1.09022
Resumen (t pareadas, Malhotra). Se observó un aumento significativo en la intención de compra tras ver el video: t(29)=5.97, p < 0.001, IC95% [0.343, 0.700], con una diferencia media de 0.522 puntos en la escala 1–7. El tamaño de efecto para pares fue d_z = 1.09 (magnitud grande), lo que indica un cambio sustantivo a nivel práctico. Con estos resultados se rechaza H0 y se concluye que el video incrementa significativamente la intención de compra de los leads; gerencialmente, conviene escalar su uso en piezas de retargeting y páginas de producto, y continuar monitoreando su desempeño en subsegmentos clave.
alpha <- 0.05
decision <- ifelse(res_t$p.value < alpha, "Se RECHAZA H0 (cambio significativo)",
"No se rechaza H0 (sin evidencia de cambio)")
cat(sprintf("**t pareadas**: t(%d)=%.2f, p=%.4f; IC95%% [%.2f, %.2f]; d_z=%.2f. %s.",
length(df_paired$dif)-1, res_t$statistic, res_t$p.value,
res_t$conf.int[1], res_t$conf.int[2], dz, decision))
t pareadas: t(29)=5.97, p=0.0000; IC95% [0.34, 0.70]; d_z=1.09. Se RECHAZA H0 (cambio significativo).
cat("\n**Conclusión de negocio**: El nuevo video demo ",
ifelse(res_t$p.value < alpha, "incrementa de forma significativa", "no muestra incremento significativo en"),
" la **intención de compra** media de los leads evaluados.", sep="")
Conclusión de negocio: El nuevo video demo incrementa de forma significativa la intención de compra media de los leads evaluados.
Idea clave. Primero haces un ANOVA: te dice si hay diferencias entre varios grupos, pero no cuáles. Ahí entra Scheffé: es un “paso extra” (post hoc = después del ANOVA) que te permite comparar grupos específicos y también combinaciones de grupos (por ejemplo, “B contra el promedio de A y C”), cuidando que no saques falsos ganadores por probar muchas cosas a la vez.
¿Qué resuelve?
- Si el ANOVA salió significativo, con Scheffé puedes
afirmar qué comparación es realmente distinta.
- Funciona bien aunque los tamaños de grupo sean
desiguales.
- Es conservadora: prefiere no aceptar a menos que la
diferencia sea clara, así protege el α (reduce falsos
positivos).
Cuándo usarla.
- Tienes ≥ 3 grupos (p. ej., creativos A, B, C).
- La métrica es continua (CTR %, tasa, puntaje).
- Quieres comparar no solo pares (A vs B), sino también
combinaciones (promedio de A y B vs C).
- Ya comprobaste con el ANOVA que sí hay diferencias
en algún lado.
Cómo leer el resultado.
- Verás una tabla con comparaciones (ej. A–B, A–C,
B–C).
- Si el p-valor de Scheffé es <
0.05, esa comparación es significativa (hay
diferencia real).
- Reporta qué grupo gana, la diferencia de
medias, el p-valor y una implicación
de negocio (p. ej., “priorizar presupuesto al creativo B frente
a A”).
Scheffé se basa en un estadístico tipo F que ajusta el umbral de significancia cuando se prueban muchas comparaciones. Se apoya en los supuestos del ANOVA (normalidad de errores, varianzas similares, independencia).
El equipo de performance quiere decidir qué creativo (A, B o C) priorizar en audiencia fría (Meta/Google Ads). Cada creativo se pauta 7–10 días con segmentos y presupuesto comparables; el CTR (%) (clics/impresiones × 100) se recoge a nivel de anuncio (múltiples anuncios por creativo). Para reducir sesgos: misma oferta y landing, frecuencia tope similar, exclusiones de remarketing, ejecución en paralelo para mitigar estacionalidad. Objetivo gerencial: detectar diferencias reales y priorizar presupuesto; si el ANOVA es significativo, usar Scheffé para comparaciones/contrastes controlando el error familiar.
A <- round(rnorm(20, mean = 2.8, sd = 0.6), 2)
B <- round(rnorm(26, mean = 3.4, sd = 0.6), 2)
C <- round(rnorm(18, mean = 3.0, sd = 0.6), 2)
df_anova <- tibble(
ctr = c(A, B, C),
creativo = factor(rep(c("A","B","C"), times = c(length(A), length(B), length(C))))
)
df_anova %>% group_by(creativo) %>% summarise(n=n(), media=mean(ctr), sd=sd(ctr))
## # A tibble: 3 × 4
## creativo n media sd
## <fct> <int> <dbl> <dbl>
## 1 A 20 2.88 0.605
## 2 B 26 3.32 0.500
## 3 C 18 3.22 0.542
ggplot(df_anova, aes(x = creativo, y = ctr)) + geom_boxplot()
leveneTest(ctr ~ creativo, data = df_anova)
## Levene's Test for Homogeneity of Variance (center = median)
## Df F value Pr(>F)
## group 2 0.4422 0.6447
## 61
Chequeos previos (boxplot + Levene).
El boxplot de ctr
por
creativo
sugiere que B y C tienden a CTR más altos que A, y
que la dispersión (altura de las cajas y bigotes) luce
comparable entre grupos. Para formalizar la igualdad de
varianzas, aplicamos Levene’s test
(car::leveneTest
) usando la mediana como
centro —una versión más robusta ante datos no
perfectamente normales. El resultado fue F(2, 61) =
0.442, p = 0.6447: como p > 0.05,
no rechazamos la hipótesis nula de homogeneidad de
varianzas. En términos prácticos (Malhotra), el
supuesto de ANOVA de varianzas iguales entre A, B y C
se cumple, por lo que podemos proceder con el ANOVA
estándar.
¿Qué es Levene’s test?
Es una prueba para evaluar si varias poblaciones tienen
varianzas iguales (homocedasticidad). Calcula, para cada
observación, su desviación absoluta respecto a una
medida de tendencia central del grupo (media o mediana,
la opción usada aquí), y luego contrasta esas desviaciones con un
ANOVA. Si el p-valor es
pequeño (< 0.05), concluimos que las varianzas
no son iguales (violación del supuesto). Si el
p-valor es grande (como en este caso),
no hay evidencia de varianzas distintas.
Nota práctica: si Levene resultara significativo, en vez del
ANOVA clásico podrías usar Welch ANOVA, transformar la
DV o aplicar métodos robustos.
fit <- aov(ctr ~ creativo, data = df_anova)
anova_tab <- summary(fit)
anova_tab
## Df Sum Sq Mean Sq F value Pr(>F)
## creativo 2 2.283 1.1417 3.826 0.0272 *
## Residuals 61 18.202 0.2984
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Post hoc Scheffé
em <- emmeans(fit, ~ creativo)
pares_scheffe <- pairs(em, adjust = "scheffe")
pares_scheffe
## contrast estimate SE df t.ratio p.value
## A - B -0.440 0.162 61 -2.707 0.0314
## A - C -0.335 0.177 61 -1.887 0.1772
## B - C 0.105 0.167 61 0.627 0.8223
##
## P value adjustment: scheffe method with rank 2
# Contraste general: (A+B)/2 vs C
contraste <- contrast(em, list(AB_vs_C = c(0.5, 0.5, -1)), adjust = "scheffe")
contraste
## contrast estimate SE df t.ratio p.value
## AB_vs_C -0.115 0.152 61 -0.755 0.4531
##
## P value adjustment: scheffe method with rank 1
ANOVA + Scheffé (resultados e interpretación). El ANOVA fue significativo: F(2, 61) = 3.826, p = 0.0272, por lo que existen diferencias en el CTR entre creativos. Con Scheffé: - A vs B: diferencia estimada = −0.440 (B > A), p = 0.0314 ⇒ significativo. - A vs C: diferencia = −0.335, p = 0.1772 ⇒ no significativo. - B vs C: diferencia = 0.105, p = 0.8223 ⇒ no significativo.
El contraste \((A+B)/2\) vs C arrojó p = 0.4531 ⇒ no significativo.
Conclusión (Malhotra): Se rechaza H0 global y, en post hoc, solo B supera a A en CTR de manera estadísticamente significativa; C no difiere de A ni de B. Recomendación gerencial: priorizar B frente a A en audiencia fría; mantener C en observación (rendimiento comparable a B pero sin evidencia concluyente). Reportar medias con IC95%, tamaño de efecto o deltas prácticos en CTR, y considerar un nuevo test con muestra balanceada para refinar la decisión entre B y C.
Fval <- anova_tab[[1]]$`F value`[1]
df1 <- anova_tab[[1]]$Df[1]
df2 <- anova_tab[[1]]$Df[2]
pval <- anova_tab[[1]]$`Pr(>F)`[1]
decision <- ifelse(pval < 0.05, "Se RECHAZA H0 (hay diferencias entre creativos)",
"No se rechaza H0 (medias similares)")
cat(sprintf("**ANOVA**: F(%d, %d)=%.2f, p=%.4f. %s\n", df1, df2, Fval, pval, decision))
ANOVA: F(2, 61)=3.83, p=0.0272. Se RECHAZA H0 (hay diferencias entre creativos)
if (pval < 0.05) {
cat("**Post hoc Scheffé (pares)**:\n")
print(as.data.frame(pares_scheffe))
cat("\n**Contraste (A+B)/2 vs C (Scheffé)**:\n")
print(as.data.frame(contraste))
}
Post hoc Scheffé (pares): contrast estimate SE df t.ratio p.value A - B -0.4398462 0.1624698 61 -2.707 0.0314 A - C -0.3348889 0.1774745 61 -1.887 0.1772 B - C 0.1049573 0.1674939 61 0.627 0.8223
P value adjustment: scheffe method with rank 2
Contraste (A+B)/2 vs C (Scheffé): contrast estimate SE df t.ratio p.value AB_vs_C -0.1149658 0.1522386 61 -0.755 0.4531
P value adjustment: scheffe method with rank 1
cat("\n**Conclusión de negocio**: Identifica el/los creativo(s) con CTR mayor de forma significativa; prioriza presupuesto hacia el/los ganador(es).")
Conclusión de negocio: Identifica el/los creativo(s) con CTR mayor de forma significativa; prioriza presupuesto hacia el/los ganador(es).
Idea clave. En una regresión, los
residuos (errores) deberían comportarse como ruido “al
azar”. El Durbin–Watson revisa si esos errores están
correlacionados en el tiempo (autocorrelación).
- El estadístico DW va de 0 a 4:
- ≈ 2 → sin autocorrelación (todo
bien).
- < 2 → autocorrelación positiva
(el error de hoy se parece al de la semana pasada).
- > 2 → autocorrelación
negativa.
¿Qué problema evita?
Si hay autocorrelación, los errores estándar de la
regresión quedan mal estimados: puedes creer que un
coeficiente es “significativo” cuando no lo es (o al revés). Es decir,
conclusiones poco confiables.
Cuándo usarlo.
- Cuando tus datos tienen orden temporal:
ventas semanales, tráfico diario, leads por día,
etc.
- Siempre que ajustes una regresión OLS con series de
tiempo, revisa DW como chequeo básico.
Cómo leerlo y actuar (regla práctica).
1. Corre la regresión (p. ej., ventas ~ inversión en medios +
precio).
2. Mira DW:
- ≈ 2 → sigue con la interpretación normal
(coeficientes, p-valores, R²).
- < 2 (común en marketing) → incorpora la
dependencia temporal:
- usar errores con estructura AR(1),
- modelos de series de tiempo (ARIMA, regresión con
errores correlacionados),
- o diferenciar/incluir rezagos de la
variable.
DW se calcula sobre los residuos del modelo y compara sus cambios de una semana a otra respecto a su variabilidad total.
Se busca cuantificar el impacto de la inversión en medios y el precio sobre las ventas semanales para decisiones de presupuesto y pricing. Serie de 26–52 semanas (misma línea de producto), cada fila es una semana calendario.
semana <- 1:26
media_inv <- round(rnorm(length(semana), mean = 12, sd = 3), 2)
precio <- round(rnorm(length(semana), mean = 9.9, sd = 0.4), 2)
ventas <- round(5 + 1.4*media_inv - 0.9*precio + rnorm(length(semana), 0, 3), 2)
df_reg <- tibble(semana, ventas, media_inv, precio)
head(df_reg, 10)
## # A tibble: 10 × 4
## semana ventas media_inv precio
## <int> <dbl> <dbl> <dbl>
## 1 1 18.3 14.2 9.76
## 2 2 22.9 16.6 10.3
## 3 3 15.8 13.5 9.54
## 4 4 11.3 12.1 9.82
## 5 5 13.1 7.6 10.2
## 6 6 24.4 15.1 9.58
## 7 7 14.4 10.2 9.26
## 8 8 15.3 14.4 10.4
## 9 9 17.5 14.6 10.4
## 10 10 12.8 13.1 9.9
m <- lm(ventas ~ media_inv + precio, data = df_reg)
summary(m)
##
## Call:
## lm(formula = ventas ~ media_inv + precio, data = df_reg)
##
## Residuals:
## Min 1Q Median 3Q Max
## -6.2574 -2.2479 -0.4778 2.3213 6.5792
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 12.7555 18.0828 0.705 0.488
## media_inv 1.5012 0.2805 5.353 1.95e-05 ***
## precio -1.7389 1.7668 -0.984 0.335
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 3.473 on 23 degrees of freedom
## Multiple R-squared: 0.5695, Adjusted R-squared: 0.532
## F-statistic: 15.21 on 2 and 23 DF, p-value: 6.18e-05
# Residuos vs ajustados
ggplot(data.frame(fitted = fitted(m), resid = resid(m)), aes(fitted, resid)) +
geom_point() + geom_hline(yintercept = 0, linetype = "dashed") +
labs(title = "Residuos vs ajustados")
# Durbin–Watson
dw <- durbinWatsonTest(m)
dw
## lag Autocorrelation D-W Statistic p-value
## 1 0.2413139 1.492642 0.166
## Alternative hypothesis: rho != 0
β (Estimate)
media_inv = 1.50
→ por cada +1 en inversión, las
ventas suben ~1.5 (manteniendo el precio
constante).precio = −1.74
→ a mayor precio, las ventas
tenderían a bajar, pero…p-value de cada β
media_inv: p < 0.001
→ efecto real
(estadísticamente significativo).precio: p = 0.335
→ no hay evidencia
de efecto con estos datos.R² = 0.569 (ajustado 0.532)
El modelo explica ~57% de la variación semanal de
ventas. Es una explicación moderada.
F-statistic (p = 6.18e−05)
El modelo, como conjunto, es mejor que no usar
predictores (significativo).
Residuos vs ajustados (gráfico)
Nube sin patrón claro alrededor de 0 → no se ve problema
grave de forma/curvatura. (Igual conviene revisar
homocedasticidad si vas a tomar decisiones finas).
Durbin–Watson = 1.49 (p = 0.166)
Valor < 2 sugiere tendencia a autocorrelación
positiva, pero con p > 0.05 no se
rechaza independencia. Úsalo como alerta suave: si vas a
decidir presupuesto, prueba una versión con errores
AR(1) por sensibilidad.
Traducido a negocio: con estos datos, invertir en medios sí mueve la aguja; el precio no muestra efecto claro aquí. El modelo es útil, pero valida la estabilidad del hallazgo con una versión que controle posible dependencia temporal.
La idea: a veces lo que pasa esta
semana se parece mucho a lo que pasó la semana
pasada.
Eso significa que los errores del modelo (lo que no
logra explicar) están encadenados en el
tiempo.
AR(1) (AutoRegresivo de orden 1) es un ajuste
que toma en cuenta esa cadena:
le dice al modelo “considera que el error de hoy se
parece al error de ayer”.
¿Para qué sirve? Si hay esa dependencia, sin
AR(1) los intervalos y p-valores pueden ser
demasiado optimistas.
Con AR(1) los resultados son más honestos cuando
trabajas con datos semanales/diarios.
“Recalculamos el modelo ajustando la memoria semana a semana. Si los hallazgos (por ejemplo, que medios ayuda) se mantienen, entonces la conclusión es sólida.”
Alternativas igual de simples:
Qué debes recordar: No necesitas “saber AR(1)” en detalle. Solo entiende que es un ajuste para series de tiempo que hace tus conclusiones más confiables cuando los datos vienen ordenados en el tiempo.
R2 <- summary(m)$r.squared
p_media <- summary(m)$coefficients["media_inv","Pr(>|t|)"]
p_precio <- summary(m)$coefficients["precio","Pr(>|t|)"]
dw_val <- dw$statistic[["DW"]]
dw_conc <- ifelse(abs(dw_val-2) < 0.3, "≈2 (sin autocorrelación)",
ifelse(dw_val < 2, "<2 (autocorrelación positiva)", ">2 (autocorrelación negativa)"))
cat(sprintf("**Regresión**: R²=%.3f; p(media_inv)=%.4f; p(precio)=%.4f.\n", R2, p_media, p_precio))
Regresión: R²=0.569; p(media_inv)=0.0000; p(precio)=0.3353.
cat(sprintf("**Durbin–Watson**: %.2f → %s.\n", dw_val, dw_conc))
cat("**Conclusión de negocio**: Mantener/incrementar inversión en medios si el coeficiente es positivo y significativo; vigilar precio si muestra efecto negativo. Si DW indica autocorrelación, ajustar el modelo (p.ej., errores AR).")
Conclusión de negocio: Mantener/incrementar inversión en medios si el coeficiente es positivo y significativo; vigilar precio si muestra efecto negativo. Si DW indica autocorrelación, ajustar el modelo (p.ej., errores AR).