knitr::opts_chunk$set(message = FALSE, warning = FALSE)
library(kableExtra)
library(knitr)
library(DescTools)
library(BoutrosLab.plotting.general)
## Loading required package: lattice
## Loading required package: latticeExtra
## Loading required package: RColorBrewer
## Loading required package: cluster
## Loading required package: hexbin
## Loading required package: grid
##
## Attaching package: 'BoutrosLab.plotting.general'
## The following object is masked from 'package:stats':
##
## dist
library(vcd)
##
## Attaching package: 'vcd'
## The following object is masked from 'package:latticeExtra':
##
## rootogram
Las pruebas de bondad de ajuste se aplican a datos de frecuencias en escalas nominales. Estos métodos nos permiten evaluar qué tan bien una muestra de observaciones de frecuencias de una población, se ajusta a una distribución hipotética de las frecuencias.
Un uso regular en biología de esta prueba, es la evaluación del resultado de cruces y las frecuencias esperadas de los fenotipos resultantes.
Ejemplo 1: Un geneticista de plantas evalúa el resultado de cruces en una población de plantas con flores amarillas y flores verdes: de un total de 100 semillas que sembró, obtuvo 84 plantas con flores amarillas y 16 con flores verdes. ¿Se ajusta este resultado a un sistema de alelos co-dominantes o a un sistema dominante-recesivo?
Este estadístico nos permite medir cuanto una muestra de una distribución observada, en escala nominal, difiere de una distribución hipotética (esperada).
\[\chi^2 = \sum_{i=1}^k\frac{(f_i - \hat f_i)^2}{\hat f_i}\] donde:
\(f_i\) es la frecuencia observada en la categoría i
\(\hat f_i\) es la frecuencia esperada en la categoría i
k es el número de categorías
Cálculos con el Ejemplo 1 A partir del Ejemplo 1 podemos establecer las siguientes hipótesis, asumiendo que esperamos una distribución según un sistema dominante-recesivo:
\(H_0\): la muestra proviene de una población con una proporción 3:1 de flores amarillas a flores verdes.
\(H_A\): la muestra proviene de una población que no tiene la proporción 3:1.
Tabla de frecuencias
amarillas | verdes | n | |
---|---|---|---|
\(f_i\) | 84 | 16 | 100 |
\((\hat f_i)\) | (75) | (25) |
#calculo de chi-cuadrado
k = 2
fm <- c(84,16)
fe <- c(75,25)
chic1 <- sum(((fm - fe)^2)/fe)
#valor critico de chi^2
nu = k - 1
chit <- qchisq(0.05,nu, lower.tail = FALSE)
chi <- data.frame(chic1,chit)
kable(chi, format = "markdown", col.names = c("chi^2 calculado", "chi^2 crítico"))
chi^2 calculado | chi^2 crítico |
---|---|
4.32 | 3.841459 |
El valor mayor de \(\chi^2\) calculado con respecto al valor crítico, nos permite rechazar la hipótesis nula, y decir que nuestra muestra no se ajusta a la proporción 3:1.
Los valores calculados de \(\chi^2\) provienen de datos discretos, y producirán valores discontinuos, sin embargo la distribución \(\chi^2\) es una función continua. Para evitar este error en el cálculo de \(\chi^2\), se utiliza una correción (Yates): \[\chi^2 = \sum_{i=1}^k\frac{(|f_i - \hat f_i| - 0.5)^2}{\hat f_i}\] Vamos a reevaluar nuestro ejemplo:
#calculo de chi-cuadrado
k = 2
fm <- c(84,16)
fe <- c(75,25)
chic1 <- sum(((abs(fm - fe) - 0.5)^2)/fe)
#chi2 de la distribución
nu = k - 1
chit <- qchisq(0.05,nu, lower.tail = FALSE)
#tabla resultados
chi <- data.frame(chic1,chit)
kable(chi, format = "markdown", col.names = c("chi^2 calculado", "chi^2 crítico"))
chi^2 calculado | chi^2 crítico |
---|---|
3.853333 | 3.841459 |
Seguimos rechazando la \(H_0\), pero con un menor margen de diferencia. La corrección de Yates debe usarse cuando \(\nu\) = 1.
chisq.test(fm, p=fe, rescale.p = TRUE, correct = TRUE)
##
## Chi-squared test for given probabilities
##
## data: fm
## X-squared = 4.32, df = 1, p-value = 0.03767
El resultado es igual - rechazamos \(H_0\) - al tener un valor de p (error tipo I) menor de 0.05. Observa que aunque se le indica a la función que realice la corrección de Yates (correct = TRUE), no lo hace porque no es necesaria en este caso, como vimos anteriormente.
En el Ejemplo 2 vamos a probar la hipótesis genética de una distribución 9:3:3:1, para un sistema dialélico con dominancia. Flor amarilla (A) y semilla lisa (L) son los alelos dominantes, mientras que flor verde (V) y semilla rugosa (R) son los alelos recesivos.
#frec observada
fo <- c(152,39,53,6)
n = sum(fo)
#frec esperada
proporcion <- c(9,3,3,1)
np = sum(proporcion)
fe <- proporcion*n/np
#crear tabla
fit <- t(fo)
fet <- t(fe)
frec <- rbind(fit,fet)
row <- c("fi","fe")
tabla <- cbind(row,frec)
knitr::kable(tabla, format = "markdown", col.names = c(" ","A-L","A-R","V-L","V-R"))
A-L | A-R | V-L | V-R | |
---|---|---|---|---|
fi | 152 | 39 | 53 | 6 |
fe | 140.625 | 46.875 | 46.875 | 15.625 |
Ahora calcularemos el valor de \(\chi^2\) y obtendremos el valor de \(\chi^2_{0.05,\nu}\) (usando qchisq o una tabla).
chick4 <- sum(((fo - fe)^2)/fe)
#chi2 de la distribución
k = 4
nu = k - 1
chit <- qchisq(0.05,nu, lower.tail = FALSE)
#tabla resultados
chi <- data.frame(chick4,chit)
kable(chi, format = "markdown", col.names = c("chi^2 calculado", "chi^2 crítico"))
chi^2 calculado | chi^2 crítico |
---|---|
8.972444 | 7.814728 |
Podemos concluir que podemos rechazar la hipótesis nula, o sea que es poco probable que se cumpla la proporción 9:3:3:1.
chisq.test(fo, p=fe, rescale.p = TRUE)
##
## Chi-squared test for given probabilities
##
## data: fo
## X-squared = 8.9724, df = 3, p-value = 0.02966
Obtenemos el mismo resultado que con el procedimiento manual, rechazamos la \(H_0\).
Cuando la cantidad de observaciones totales (n) no es muy grande, o cuando algún valor de \(|f_i - \hat f_i| \geq \hat f_i\), se recomienda el uso del estadístico G en lugar de \(\chi^2\). Este estadístico se calcula de la siguiente manera: \[G = 2\sum f_i ln \frac{f_i}{\hat f_i}\] o su equivalente: \[G = 2[\sum{f_i ln f_i} - \sum{f_i ln \hat f_i}]\]
Vamos a usar los datos del Ejemplo 2 para la prueba de hipótesis usando G.
#frec observada
fo <- c(152,39,53,6)
n = sum(fo)
#frec esperada
proporcion <- c(9,3,3,1)
np = sum(proporcion)
fe <- proporcion*n/np
#crear tabla
fit <- t(fo)
fet <- t(fe)
frec <- rbind(fit,fet)
row <- c("fi","fe")
tabla <- cbind(row,frec)
knitr::kable(tabla, format = "markdown", col.names = c(" ","A-L","A-R","V-L","V-R"))
A-L | A-R | V-L | V-R | |
---|---|---|---|---|
fi | 152 | 39 | 53 | 6 |
fe | 140.625 | 46.875 | 46.875 | 15.625 |
#calculo de G
G <- 2*sum(fo*log(fo/fe))
sprintf("G calculada: %.3f", G)
## [1] "G calculada: 10.833"
k = 4
nu = k - 1
chit <- qchisq(0.05,nu, lower.tail = FALSE)
sprintf("chi-cuadrado(0.05,3): %.3f", chit)
## [1] "chi-cuadrado(0.05,3): 7.815"
Con el estadístico G también podemos concluir que rechazamos con seguridad la hipótesis nula 9:3:3:1.
#pasar proporciones teóricas a probabilidades
prob1 <- proporcion/sum(proporcion)
# o pasar frecuencias esperadas a probabilidades
prob2 <- fe/sum(fe)
GTest(x=fo, p=prob1, correct="none")
##
## Log likelihood ratio (G-test) goodness of fit test
##
## data: fo
## G = 10.833, X-squared df = 3, p-value = 0.01267
Obtenemos los mismos resultados que con el cálculo manual.
En las pruebas anteriores se comparan las frecuencias de la muestra y esperada, en una categoría nominal. La prueba de Kolmogorov-Smirnov nos permite comparar frecuencias observadas y esperadas, en escalas de proporciones (acumuladas), ordinales o intervalos. Esta prueba también se usa para probar si las distribuciones de dos muestras de valores continuos, son iguales o no (provienen o no de la misma población).
Para esta prueba se necesita calcular la frecuencia relativa observada acumulada de la variable observada: \[rel\ F_i = \frac{F_i}{n}\] donde:
\(F_i\) es la frecuencia acumulada observada hasta un valor de la escala continua, \(X_i\)
\(n\) es el total de observaciones realizadas a lo largo de la escala continua
La frecuencia relativa esperada acumulada se calcula a partir de la distribución esperada a lo largo de una escala continua: \[rel\ \hat F_i = \frac{X_i}{X_{máximo}}\]
El Ejemplo 3 se refiere a la distribución de mariposas en un árbol (Figura 1).
Figura 1. Distribución de mariposas a lo largo de un árbol. \(X_i\) es la distancia (m) desde el suelo a la que se encuentran \(f_i\) mariposas (frecuencia). Nota: solo se muestran algunos de los datos.
Datos de altura (m) a la que se observan las mariposas, \(X_i\), y número (frecuencia) de mariposas (\(f_i\)) observadas a la altura correspondiente. Queremos probar la hipótesis nula de que las mariposas se distribuyen uniformemente a lo largo de la altura del árbol (hasta 25 m), versus la hipótesis alterna de que las mariposas no se distribuyen uniformemente.
## [1] "Xi:"
## [1] 1.4 2.6 3.3 4.2 4.7 5.6 6.4 7.7 9.3 10.6 11.5 12.4 18.6 22.3
## [1] "fi:"
## [1] 1 1 1 1 1 2 1 1 1 1 1 1 1 1
Table 1. Frecuencia relativa acumulada de mariposas (\(rel\ F_i\)), frecuencia relativa acumulada de altura (\(rel\ \hat F_i\)), estadístico para la prueba de Kolmogorov-Smirnov: \(D_i = |rel\ F_i - rel\ \hat F_i|\).
#secuencia
i <- c(seq(1:14))
#frecuencia acumulada de mariposas
fiac <- cumsum(fi)
#frecuencia relativa acumulada de mariposas
firelac <- fiac/15
#frecuencia relativa acumulada de la altura
xirelac <- xi/25
#estadístico Di
di <- abs(firelac - xirelac)
#tabla de resultados
tablaKS <- data.frame(i, xi, fi, fiac, firelac, xirelac, di)
kable(tablaKS, format = "markdown", col.names = c("i","Xi","fi","Fi","rel F_i","rel F^_i","Di"))
i | Xi | fi | Fi | rel F_i | rel F^_i | Di |
---|---|---|---|---|---|---|
1 | 1.4 | 1 | 1 | 0.0666667 | 0.056 | 0.0106667 |
2 | 2.6 | 1 | 2 | 0.1333333 | 0.104 | 0.0293333 |
3 | 3.3 | 1 | 3 | 0.2000000 | 0.132 | 0.0680000 |
4 | 4.2 | 1 | 4 | 0.2666667 | 0.168 | 0.0986667 |
5 | 4.7 | 1 | 5 | 0.3333333 | 0.188 | 0.1453333 |
6 | 5.6 | 2 | 7 | 0.4666667 | 0.224 | 0.2426667 |
7 | 6.4 | 1 | 8 | 0.5333333 | 0.256 | 0.2773333 |
8 | 7.7 | 1 | 9 | 0.6000000 | 0.308 | 0.2920000 |
9 | 9.3 | 1 | 10 | 0.6666667 | 0.372 | 0.2946667 |
10 | 10.6 | 1 | 11 | 0.7333333 | 0.424 | 0.3093333 |
11 | 11.5 | 1 | 12 | 0.8000000 | 0.460 | 0.3400000 |
12 | 12.4 | 1 | 13 | 0.8666667 | 0.496 | 0.3706667 |
13 | 18.6 | 1 | 14 | 0.9333333 | 0.744 | 0.1893333 |
14 | 22.3 | 1 | 15 | 1.0000000 | 0.892 | 0.1080000 |
Para la prueba de hipótesis calculamos el valor máximo de \(D_i\), para compararlo con el valor crítico del estadístico: \(D_{0.05(2),n}\). D se obtiene a partir de una tabla o mediante la función ks.test.critical.value(n, p, alternative = “one-sided” (or “two-sided”)).
#valor máximo de Di
dmax <- max(di)
#D de la distribución
n = 15
p = 0.95
dcrit <- ks.test.critical.value(n, p, alternative = "two-sided")
tablaKStest <- data.frame(dmax,n, p, dcrit)
kable(tablaKStest, format = "markdown", col.names = c("D máximo", "n", "p", "D crítico"))
D máximo | n | p | D crítico |
---|---|---|---|
0.3706667 | 15 | 0.95 | 0.3375964 |
El valor de D máximo es mayor que el D crítico, por lo tanto rechazamos la \(H_0\), y podemos decir que las mariposas no tienen una distribución uniforme a lo largo de la altura del árbol.
La tabla de contingencia es parte de un procedimiento para probar la independencia entre variables nominales. La forma más común para probar la independencia es con el uso del estadístico \(\chi^2\). La forma más común de calcularlo es: \[\chi^2 = \sum_{i=1}^r \sum_{j=1}^c \frac{(f_{ij} - \hat f_{ij})^2}{\hat f_{ij}}\] donde:
\(f_{ij}\) es la frecuencia observada de la fila i, columna j
\(\hat f_{ij}\) es la frecuencia esperada de la fila i, columan j
c es el número de columnas
r es el número de filas (‘rows’)
Para calcular las frecuencias esperadas es necesario primero calcular las frecuencias totales de las filas (\(R_i\)) y de las columnas (\(C_j\)); para esto usamos las fórmulas: \[R_i = \sum_{j=1}^c f_{ij}\] \[C_j = \sum_{i=1}^r f_{ij}\] A partir de estos valores, podemos calcular cada frecuencia esperada: \[\hat f_{ij} = \frac{(R_i)(C_j)}{n}\] donde n es l número total de observaciones.
Una vez calculado el valor de \(\chi^2\), debemos compararlo con el valor crítico de la tabla (o función de R) para un nivel de significancia determinado (usualmente 0.05) y \(\nu = (r - 1)(c - 1)\).
Ejemplo 4. Queremos probar la independencia entre la característica color de pelo y sexo, en 300 humanos, seleccionando al azar 100 hombres y 200 mujeres.
color de pelo | |||||
---|---|---|---|---|---|
sexo | NEGRO | MARRON | RUBIO | ROJO | total |
HOMBRE | 32 | 43 | 16 | 9 | 100 = \(R_1\) |
MUJER | 55 | 65 | 64 | 16 | 200 = \(R_2\) |
total | 87 = \(C_1\) | 108 = \(C_2\) | 80 = \(C_3\) | 25 = \(C_4\) | 300 = \(n\) |
La forma más general de plantear la hipótesis de independencia es: \(H_0\): el color del pelo es independiente del sexo en la población muestreada, y \(H_A\): el color del pelo no es independiente del sexo en la población muestreada.
Calculamos las frecuencias esperadas para calcular luego el estadístico \(\chi^2\).
Ri <- c(100,200)
Ci <- c(87,108,80,25)
mfe <- (Ri%*%t(Ci))/300
fe <- as.data.frame(mfe)
sexo <- c("Hombre","Mujer")
colnames(fe) <- c("Negro","Marrón","Rubio","Rojo")
tablafe <- cbind(sexo,fe)
kable(tablafe, format = "markdown", caption = "Frecuencias Esperadas")
sexo | Negro | Marrón | Rubio | Rojo |
---|---|---|---|---|
Hombre | 29 | 36 | 26.66667 | 8.333333 |
Mujer | 58 | 72 | 53.33333 | 16.666667 |
#matriz de frecuencia esperada es mfe
#definimos matriz frecuencias observadas
mfo <- matrix(c(32,43,16,9,55,65,64,16), ncol = 4, byrow = TRUE)
#cálculo de chi-cuadrado
chicu2 = 0
for(i in 1:2){
for(j in 1:4){
chicu1 = sum(((mfo[i,j] - mfe[i,j])^2)/mfe[i,j])
chicu2 = chicu2 + chicu1
}
}
#chi-cuadrado critico de función (o tabla)
r = 2
c = 4
nu = (r-1)*(c-1)
chicri <- qchisq(0.05,nu, lower.tail = FALSE)
chitest <- data.frame(chicu2,nu,chicri)
colnames(chitest) <- c("Chi^2 calculado", "grados de libertad", "Chi^2 crítico")
kable(chitest, format = "markdown")
Chi^2 calculado | grados de libertad | Chi^2 crítico |
---|---|---|
8.987184 | 3 | 7.814728 |
El valor calculado de \(\chi^2\) resultó mayor que el valor crítico, por lo tanto rechazamos la hipótesis nula de independencia, y podemos esperar que el color del pelo no sea independiente del sexo.
#data frame desde matriz de datos
fo <- as.data.frame(mfo)
chisq.test(fo)
##
## Pearson's Chi-squared test
##
## data: fo
## X-squared = 8.9872, df = 3, p-value = 0.02946
Ahora bien, la prueba estadística solo nos indica si se acepta o rechaza la hipótesis nula, pero no nos específica dónde están las principales discrepancias entre las frecuencias, por efecto de la no-independencia entre los variables nominales. Una gráfica de mosaico puede ayudarnos a identificar las categorías entre las que se producen las mayores discrepancias.
mosaic(mfo, shade = TRUE, legend = FALSE, labeling_args = list(set_varnames = c(A = "Sexo", B = "Color Pelo")), set_labels = list(A = c("Hombre","Mujer"), B = c("Negro","Marrón","Rubio","Rojo")))