Objetivo. Documento listo para RPubs con: (1) Bondad de ajuste para un dado (uniforme), (2) Bondad de ajuste a Normal con clases por intervalos, (3) Independencia en 2×3 (Opinión×Ingreso). Incluye tablas, gráficos e interpretaciones tipo APA.
Nota: Se evitaron referencias inline a objetos para prevenir errores de knit; todas las conclusiones se imprimen dentro de chunks ejecutables.

1 0) Setup

# Paquetes
instalar_si_falta <- function(pkgs){
  falta <- pkgs[!pkgs %in% rownames(installed.packages())]
  if(length(falta)) install.packages(falta, dependencies = TRUE)
}
instalar_si_falta(c("ggplot2","dplyr","tidyr","scales","knitr"))

suppressPackageStartupMessages({
  library(ggplot2); library(dplyr); library(tidyr); library(scales); library(knitr)
})
theme_set(theme_minimal(base_size = 12))
set.seed(123)

2 1) Bondad de ajuste — Dado justo (uniforme)

Planteo del problema. Se tira un dado legal 120 veces. Bajo \(H_0\) las probabilidades son uniformes \(p_i=1/6\). Se observan las frecuencias: 20, 22, 17, 18, 19, 24.

Hipótesis.
- \(H_0\): \(P(1)=\cdots=P(6)=1/6\) (dado justo).
- \(H_1\): al menos una probabilidad difiere.

Estadístico. \(\chi^2=\sum (o_i-e_i)^2/e_i\); \(gl=k-1=5\).

# Datos y test
obs <- c(20, 22, 17, 18, 19, 24)
esp <- rep(20, 6)

chisq_test <- chisq.test(x = obs, p = rep(1/6, 6))

# Cálculo manual y p-valor
chi2_calc <- sum((obs - esp)^2 / esp)
gl <- length(obs) - 1
p_value <- pchisq(chi2_calc, df = gl, lower.tail = FALSE)

# Tabla obs–esp
data.frame(Cara = 1:6, Observada = obs, Esperada = esp) |>
  kable(digits = 1, caption = "Dado: frecuencias observadas y esperadas")
Dado: frecuencias observadas y esperadas
Cara Observada Esperada
1 20 20
2 22 20
3 17 20
4 18 20
5 19 20
6 24 20
# Conclusión en formato APA
cat(sprintf("\n**Conclusión (APA):** χ²(%d) = %.2f, p = %.3f.\n", gl, chi2_calc, p_value))
## 
## **Conclusión (APA):** χ²(5) = 1.70, p = 0.889.
if(p_value >= 0.05){
  cat("No se rechaza H0: el dado se comporta como uniforme.\n")
} else {
  cat("Se rechaza H0: evidencia de dado no uniforme.\n")
}
## No se rechaza H0: el dado se comporta como uniforme.

Gráfico.

df <- data.frame(cara=factor(1:6), Observada=obs, Esperada=esp)
df_long <- tidyr::pivot_longer(df, -cara, names_to="Tipo", values_to="Frecuencia")

ggplot(df_long, aes(cara, Frecuencia, fill=Tipo)) +
  geom_col(position="dodge") +
  labs(title="Bondad de ajuste: dado justo", x="Cara", y="Frecuencia") +
  theme_minimal()


3 2) Bondad de ajuste a distribución Normal (clases por intervalos)

Planteo del problema. Se miden 40 duraciones de baterías. Se propone \(X\sim N(\mu=3.5,\sigma=0.7)\) y se agrupan observaciones en clases de 0.5 unidades entre 1.45 y 4.95.

Hipótesis.
- \(H_0\): la población sigue \(N(3.5,0.7^2)\).
- \(H_1\): no sigue esa Normal.

set.seed(123)
x <- rnorm(40, mean = 3.5, sd = 0.7)
breaks <- seq(1.45, 4.95, by = 0.5)
oi <- as.numeric(table(cut(x, breaks, include.lowest = TRUE)))
ei <- diff(pnorm(breaks, mean = 3.5, sd = 0.7)) * 40

tabla_norm <- data.frame(Intervalo = paste(head(breaks,-1), tail(breaks,-1), sep="-"),
                         Observadas = oi, Esperadas = round(ei,1))
kable(tabla_norm, caption = "Frecuencias por clase: observadas y esperadas (Normal teórica)")
Frecuencias por clase: observadas y esperadas (Normal teórica)
Intervalo Observadas Esperadas
1.45-1.95 0 0.5
1.95-2.45 2 2.1
2.45-2.95 4 6.0
2.95-3.45 12 10.2
3.45-3.95 11 10.7
3.95-4.45 8 6.9
4.45-4.95 3 2.7
# Advertencia sobre esperadas
if(any(ei < 5)){
  cat("\n**Aviso:** hay esperadas < 5; combinar clases contiguas antes de aplicar χ² para garantizar validez.\n")
}
## 
## **Aviso:** hay esperadas < 5; combinar clases contiguas antes de aplicar χ² para garantizar validez.
# Test (equivalente a usar ei/sum(ei) como probabilidades teóricas)
gof_norm <- chisq.test(oi, p = ei/sum(ei))
gof_norm
## 
##  Chi-squared test for given probabilities
## 
## data:  oi
## X-squared = 1.5893, df = 6, p-value = 0.9533
# Conclusión APA
cat(sprintf("\n**Conclusión (APA):** χ²(%d) = %.2f, p = %.3f.\n",
            gof_norm$parameter, gof_norm$statistic, gof_norm$p.value))
## 
## **Conclusión (APA):** χ²(6) = 1.59, p = 0.953.
if(gof_norm$p.value >= 0.05){
  cat("No se rechaza H0: la Normal propuesta ajusta razonablemente los datos.\n")
} else {
  cat("Se rechaza H0: la Normal propuesta no explica adecuadamente las frecuencias.\n")
}
## No se rechaza H0: la Normal propuesta ajusta razonablemente los datos.

4 3) Independencia — Opinión × Nivel de ingreso (2×3)

Planteo. ¿Son independientes la Opinión sobre una reforma fiscal (A favor / En contra) y el Nivel de ingreso (Bajo / Medio / Alto) en una muestra de 1000 votantes?

Hipótesis.
- \(H_0\): Opinión e Ingreso son independientes.
- \(H_1\): Existe asociación entre ambas.

tabla <- matrix(c(182,213,203,154,138,110), nrow=2, byrow=TRUE)
colnames(tabla) <- c("Bajo","Medio","Alto")
rownames(tabla) <- c("A favor","En contra")

kable(as.data.frame.matrix(tabla), caption = "Tabla 2×3: Opinión × Ingreso", align = "r")
Tabla 2×3: Opinión × Ingreso
Bajo Medio Alto
A favor 182 213 203
En contra 154 138 110
chisq_indep <- chisq.test(tabla)
chisq_indep
## 
##  Pearson's Chi-squared test
## 
## data:  tabla
## X-squared = 7.8782, df = 2, p-value = 0.01947
chisq_indep$expected
##              Bajo   Medio    Alto
## A favor   200.928 209.898 187.174
## En contra 135.072 141.102 125.826
# Tamaño de efecto (V de Cramér)
cramers_v <- function(tab){
  chi2 <- suppressWarnings(chisq.test(tab)$statistic)
  n <- sum(tab); r <- nrow(tab); c <- ncol(tab)
  as.numeric(sqrt(chi2 / (n * (min(r,c)-1))))
}
V <- cramers_v(tabla)

# Conclusión APA
cat(sprintf("\n**Conclusión (APA):** χ²(%d) = %.2f, p = %.3f; V de Cramér = %.3f; n = %d.\n",
            chisq_indep$parameter, chisq_indep$statistic, chisq_indep$p.value, V, sum(tabla)))
## 
## **Conclusión (APA):** χ²(2) = 7.88, p = 0.019; V de Cramér = 0.089; n = 1000.

Gráfico de proporciones por fila.

prop.table(tabla, margin=1) |> 
  as.data.frame.table() |> 
  ggplot(aes(x=Var2, y=Freq, fill=Var1)) +
  geom_col(position="dodge") +
  labs(
    title="Opinión sobre reforma fiscal por nivel de ingreso",
    x="Nivel de ingreso",
    y="Proporción dentro de cada grupo",
    fill="Opinión"
  ) +
  coord_cartesian(ylim = c(0, 1)) +
  theme_minimal()

Diagnóstico por celdas (post‑hoc con residuales).

res_std <- chisq_indep$stdres
p_res   <- 2 * pnorm(-abs(res_std))
p_adj   <- p.adjust(p_res, method = "bonferroni")
list(
  ResidualesEstandarizados = round(res_std, 2),
  P_sin_ajuste = round(p_res, 4),
  P_ajustada_Bonferroni = round(matrix(p_adj, nrow = nrow(tabla), dimnames = dimnames(tabla)), 4)
)
## $ResidualesEstandarizados
##            Bajo Medio Alto
## A favor   -2.58  0.42  2.2
## En contra  2.58 -0.42 -2.2
## 
## $P_sin_ajuste
##             Bajo  Medio   Alto
## A favor   0.0098 0.6751 0.0277
## En contra 0.0098 0.6751 0.0277
## 
## $P_ajustada_Bonferroni
##             Bajo Medio   Alto
## A favor   0.0585     1 0.1663
## En contra 0.0585     1 0.1663

5 4) Publicación en RPubs — Pasos

  1. KnitHTML.
  2. En el visor de RStudio, clic en PublishRPubs.
  3. Definí título y (opcional) palabras clave.
  4. Copiá la URL para tus estudiantes.

6 Apéndice: Script compacto (copiar/pegar)

# Bondad de ajuste (uniforme)
obs <- c(20,22,17,18,19,24); esp <- rep(20,6)
chisq.test(obs, p = rep(1/6,6))
chi2_calc <- sum((obs - esp)^2 / esp); gl <- length(obs)-1
p_value <- pchisq(chi2_calc, df=gl, lower.tail=FALSE)
cat(sprintf("χ²(%d)=%.2f, p=%.3f\n", gl, chi2_calc, p_value))

# GoF a Normal con clases
set.seed(123); x <- rnorm(40, 3.5, 0.7)
breaks <- seq(1.45, 4.95, 0.5)
oi <- as.numeric(table(cut(x, breaks, include.lowest=TRUE)))
ei <- diff(pnorm(breaks, 3.5, 0.7)) * 40
chisq.test(oi, p = ei/sum(ei))

# Independencia 2×3
tabla <- matrix(c(182,213,203,154,138,110), 2, byrow=TRUE)
colnames(tabla) <- c("Bajo","Medio","Alto"); rownames(tabla) <- c("A favor","En contra")
chisq_indep <- chisq.test(tabla)
cramers_v <- function(tab){ chi2 <- suppressWarnings(chisq.test(tab)$statistic)
  n <- sum(tab); r <- nrow(tab); c <- ncol(tab); sqrt(chi2 / (n * (min(r,c)-1))) }
V <- cramers_v(tabla)
cat(sprintf("χ²(%d)=%.2f, p=%.3f; V=%.3f\n", chisq_indep$parameter, chisq_indep$statistic, chisq_indep$p.value, V))