pacman::p_load(tidyverse,GGally,esquisse,ggThemeAssist,summarytools,readxl,viridis,hrbrthemes,car,nortest,nnet)
BD2_R <- read_excel("BD2_R.xlsx")
BD2 <- BD2_R Módulo VI
Taller de IA y CD
1 Estadística Descriptiva
En esta sección se dará un breve repaso de los resúmenes que hemos hecho en el pre-procesado, pero se agregarán las funciones para extraer la estadística de interés, además de exportarla a un formato más manejable.
1.1 Visualización de la Base
Cargamos bases y librerías:
En primer lugar, recordemos que debemos conocer cómo se encuentra constituida nuestra base de datos. Para ellos se hace lo siguiente:
BD_clases <- sapply(BD2, class)
info_cols <- data.frame(
Columna = names(BD_clases),
Clase = unname(BD_clases)
)
print(info_cols) Columna Clase
1 id character
2 colesterol numeric
3 glucosa numeric
4 hdl numeric
5 col_hdl_ratio numeric
6 hb1ac numeric
7 diabetes_log logical
8 lugar_origen character
9 edad numeric
10 sexo character
11 altura numeric
12 peso numeric
13 imc numeric
14 act_fisica_fac character
15 tx_ta logical
16 tas_1 numeric
17 tad_1 numeric
18 tas_2 numeric
19 tad_2 numeric
20 cintura numeric
21 cadera numeric
Ahora recordamos el tipo de dato de cada variable.
Ahora demos un vistazo a las variables:
summary(BD2) id colesterol glucosa hdl
Length:403 Min. : 78.0 Min. : 48.0 Min. : 12.00
Class :character 1st Qu.:179.0 1st Qu.: 81.0 1st Qu.: 38.00
Mode :character Median :204.0 Median : 89.0 Median : 46.00
Mean :207.8 Mean :106.7 Mean : 50.45
3rd Qu.:230.0 3rd Qu.:106.0 3rd Qu.: 59.00
Max. :443.0 Max. :385.0 Max. :120.00
NA's :1 NA's :1
col_hdl_ratio hb1ac diabetes_log lugar_origen
Min. : 1.500 Min. : 2.68 Mode :logical Length:403
1st Qu.: 3.200 1st Qu.: 4.38 FALSE:325 Class :character
Median : 4.200 Median : 4.84 TRUE :65 Mode :character
Mean : 4.522 Mean : 5.59 NA's :13
3rd Qu.: 5.400 3rd Qu.: 5.60
Max. :19.300 Max. :16.11
NA's :1 NA's :13
edad sexo altura peso
Min. :19.00 Length:403 Min. :1.321 Min. : 0.00
1st Qu.:34.00 Class :character 1st Qu.:1.600 1st Qu.: 66.22
Median :45.00 Mode :character Median :1.676 Median : 80.29
Mean :46.85 Mean :1.677 Mean : 82.41
3rd Qu.:60.00 3rd Qu.:1.753 3rd Qu.: 93.89
Max. :92.00 Max. :1.930 Max. :169.64
NA's :5
imc act_fisica_fac tx_ta tas_1
Min. : 0.00 Length:403 Mode :logical Min. : 90.0
1st Qu.:23.89 Class :character FALSE:141 1st Qu.:121.2
Median :28.10 Mode :character TRUE :262 Median :136.0
Mean :29.39 Mean :136.9
3rd Qu.:33.88 3rd Qu.:146.8
Max. :64.20 Max. :250.0
NA's :5 NA's :5
tad_1 tas_2 tad_2 cintura
Min. : 48.00 Min. : 92.0 Min. : 49.00 Min. : 66.04
1st Qu.: 75.00 1st Qu.:129.0 1st Qu.: 76.00 1st Qu.: 83.82
Median : 82.00 Median :140.0 Median : 85.00 Median : 93.98
Mean : 83.32 Mean :144.4 Mean : 85.17 Mean : 96.27
3rd Qu.: 90.00 3rd Qu.:158.0 3rd Qu.: 94.00 3rd Qu.:104.14
Max. :124.00 Max. :238.0 Max. :129.00 Max. :142.24
NA's :5 NA's :6 NA's :6 NA's :2
cadera
Min. : 76.20
1st Qu.: 99.06
Median :106.68
Mean :109.32
3rd Qu.:116.84
Max. :162.56
NA's :2
Ya tenemos un mini resumen descriptivo.
Ahora veamos las variables categóricas:
BD2 [-1] %>%
select_if(is.character) %>%
sapply(unique)$lugar_origen
[1] "Jal" "Mor" "Ags"
$sexo
[1] "mujer" "hombre"
$act_fisica_fac
[1] "Bajo" "Sedentario" "Alto" NA
Recordemos que la primera variable es el id, por lo que no la deseamos ver. Usamos la función “select_if” para que si cumple con una condición (que es “is.character”), lleve a cabo la siguiente operación, que es “sapply”, valores únicos.
También lo podemos usar para ver variables de tipo numérico, lógico, factor…
Ahora, usemos el resumen gráfico que habíamos trabajado:
view(dfSummary(BD2))Switching method to 'browser'
Output file written: C:\Users\Hack\AppData\Local\Temp\RtmpQHYhN9\file708511514be.html
Bueno, ya tenemos un vistazo de nuestra base de datos, y ahora recordemos que podemos hacer resúmenes estadísticos con el mismo paquete de summarytools. Hagamos una estadística descriptiva por tipo de variable en dos objetos diferentes:
BD2_descr <- descr(BD2, transpose = T, stats = "common")
BD2_freq <- freq(BD2[-1])
BD2_descrNon-numerical variable(s) ignored: id, diabetes_log, lugar_origen, sexo, act_fisica_fac, tx_ta
Descriptive Statistics
BD2
N: 403
Mean Std.Dev Min Median Max N.Valid N Pct.Valid
------------------- -------- --------- ------- -------- -------- --------- -------- -----------
altura 1.68 0.10 1.32 1.68 1.93 398.00 403.00 98.76
cadera 109.32 14.37 76.20 106.68 162.56 401.00 403.00 99.50
cintura 96.27 14.55 66.04 93.98 142.24 401.00 403.00 99.50
col_hdl_ratio 4.52 1.73 1.50 4.20 19.30 402.00 403.00 99.75
colesterol 207.85 44.45 78.00 204.00 443.00 402.00 403.00 99.75
edad 46.85 16.31 19.00 45.00 92.00 403.00 403.00 100.00
glucosa 106.67 53.08 48.00 89.00 385.00 403.00 403.00 100.00
hb1ac 5.59 2.24 2.68 4.84 16.11 390.00 403.00 96.77
hdl 50.45 17.26 12.00 46.00 120.00 402.00 403.00 99.75
imc 29.39 7.84 0.00 28.10 64.20 398.00 403.00 98.76
peso 82.41 22.35 0.00 80.29 169.64 403.00 403.00 100.00
tad_1 83.32 13.59 48.00 82.00 124.00 398.00 403.00 98.76
tad_2 85.17 12.64 49.00 85.00 129.00 397.00 403.00 98.51
tas_1 136.90 22.74 90.00 136.00 250.00 398.00 403.00 98.76
tas_2 144.40 21.15 92.00 140.00 238.00 397.00 403.00 98.51
En la función de “stats” podemos seleccionar “common”, la cual contiene las estadísticas habitualmente utilizadas.
Naturalmente, queremos guardarlo para ponerlo en nuestros informes, esto se logra así:
capture.output (BD2_descr, file = "BD2_numéricas.txt")Non-numerical variable(s) ignored: id, diabetes_log, lugar_origen, sexo, act_fisica_fac, tx_ta
capture.output (BD2_freq, file = "BD2_categóricas.txt")Variable(s) ignored: colesterol, glucosa, hdl, col_hdl_ratio, hb1ac, edad, peso, imc
Podemos guardar nuestros resúmenes ya sea en formato .txt o word (.doc), solo hay que cambiar la extensión. La función de “capture.output” nos permite guardar objetos que tienen contenido de tipo de texto.
Ya tenemos estadística descriptiva básica y el método para exportarlo a nuestra computadora. Ahora, realizaremos en orden las pruebas habituales que se hacen previo a la pruebas estadísticas normales.
Hagamos ahora dos ejercicios:
Hagan un dfsummary con la base completa.
Hagan un ggpairs con la base completa (quiten el id).
Pueden utilizar los códigos que hemos trabajado en días previos.
Para fines del curso, solamente se mostrará el cómo realizar en R cada prueba mencionada sin considerar si es la más adecuada o no por el tipo de dato.
1.2 Pruebas de Ajuste
1.2.1 Pruebas de Normalidad
Las pruebas de normalidad se realizan para evaluar si una variable numérica presenta una distribución paramétrica. Previo a la pruebas como tal, se puede evaluar mediante un histograma o un QQ-plot. Como ya contamos el conocimiento base del histograma, pasemos al QQ-plot.
variables <- BD2[-1] %>%
select_if(
is.numeric
) %>%
colnames()
plots <- lapply(variables,
function(var) {
ggplot(BD2,
aes(sample = .data[[var]]
)
) +
stat_qq(color = "blue4") +
stat_qq_line(color = "green4") +
ggtitle(paste("QQ-Plot para", var))
})
plots[[1]]

[[2]]

[[3]]

[[4]]

[[5]]

[[6]]

[[7]]

[[8]]

[[9]]

[[10]]

[[11]]

[[12]]

[[13]]

[[14]]

[[15]]

En el código anterior primero generamos un objeto llamado “variables” que contenga un vector con los nombres de las variables que son de tipo numérico.
En la segunda sección, primero creamos un objeto que se va a llamar “plots”. Luego hacemos una “lapply” (list apply) que utiliza el objeto “variables” y se le va a aplicar una función con un nombre genérico, que es “var” (puede ser el que tú quieras). Llamamos la librería “ggplot” de forma habitual, y para el aes usamos una función “sample = .data[[var]]” que es similar a usar el símbolo de “$” para llamar una columna, pero como queremos automatizar todo a través del vector, usamos este método. Hacemos llamado para la función de la distribución de nuestros datos en puntos y la distribución normal con línea con “stat_qq” y “stat_qq_line”, respectivamente. Finalmente, usamos “ggtitle(paste(”QQ-Plot para”, var” para hacer títulos genéricos que empiezan con “QQ-Plot para” e inmediatamente se pega el nombre de la variable tal como viene en nuestro vector.
Naturalmente, es un código un poco extenso, pero lo puedes reutilizar y solamente pegas el nombre de tu base de datos.
Ahora, procedemos a la prueba de normalidad, asumamos que queremos realizar la prueba de Shapiro-Wilk:
shapiro.test(BD2$colesterol)
Shapiro-Wilk normality test
data: BD2$colesterol
W = 0.95939, p-value = 4.296e-09
Naturalmente, podemos realizar la prueba de Kolmogorv-Smirnov, hay que considerar que como existen valores repetidos, nos va a arrojar un error:
ks.test(BD2$colesterol, 'pnorm')Warning in ks.test.default(BD2$colesterol, "pnorm"): ties should not be present
for the one-sample Kolmogorov-Smirnov test
Asymptotic one-sample Kolmogorov-Smirnov test
data: BD2$colesterol
D = 1, p-value < 2.2e-16
alternative hypothesis: two-sided
También podemos llevar a cabo la prueba de Anderson-Darling, la cual se puede ajustar a nuestra variable:
ad.test(BD2$colesterol)
Anderson-Darling normality test
data: BD2$colesterol
A = 2.7829, p-value = 5.149e-07
Por supuesto, podemos usar la función “sapply” para generar las pruebas de normalidad a todo:
BD2 %>%
select_if(is.numeric) %>%
sapply(shapiro.test) colesterol glucosa
statistic 0.9593867 0.6476578
p.value 4.295804e-09 5.454664e-28
method "Shapiro-Wilk normality test" "Shapiro-Wilk normality test"
data.name "X[[i]]" "X[[i]]"
hdl col_hdl_ratio
statistic 0.9235699 0.8696703
p.value 1.917537e-13 7.226449e-18
method "Shapiro-Wilk normality test" "Shapiro-Wilk normality test"
data.name "X[[i]]" "X[[i]]"
hb1ac edad
statistic 0.7218346 0.9755724
p.value 5.512283e-25 2.653284e-06
method "Shapiro-Wilk normality test" "Shapiro-Wilk normality test"
data.name "X[[i]]" "X[[i]]"
altura peso
statistic 0.98794 0.9533511
p.value 0.002227658 5.569332e-10
method "Shapiro-Wilk normality test" "Shapiro-Wilk normality test"
data.name "X[[i]]" "X[[i]]"
imc tas_1
statistic 0.9502796 0.9376639
p.value 2.586659e-10 7.306905e-12
method "Shapiro-Wilk normality test" "Shapiro-Wilk normality test"
data.name "X[[i]]" "X[[i]]"
tad_1 tas_2
statistic 0.9904326 0.9523933
p.value 0.01091829 5.161281e-10
method "Shapiro-Wilk normality test" "Shapiro-Wilk normality test"
data.name "X[[i]]" "X[[i]]"
tad_2 cintura
statistic 0.9943093 0.9788179
p.value 0.1464415 1.326393e-05
method "Shapiro-Wilk normality test" "Shapiro-Wilk normality test"
data.name "X[[i]]" "X[[i]]"
cadera
statistic 0.9592809
p.value 4.290232e-09
method "Shapiro-Wilk normality test"
data.name "X[[i]]"
Puedes cambiar la prueba de normalidad que desees dentro de la función de “sapply”.
1.2.2 Pruebas de Homocedasticidad
Las pruebas de homocedasticidad describen si diferentes grupos presentan varianzas iguales, la prueba de Levene para distribuciones no paramétricas se lleva a cabo de la siguiente manera:
leveneTest(hdl ~ sexo, data = BD2)Warning in leveneTest.default(y = y, group = group, ...): group coerced to
factor.
Levene's Test for Homogeneity of Variance (center = median)
Df F value Pr(>F)
group 1 0.7902 0.3746
400
La sintaxis es llamar la función “leveneTest”, primero la variable numérica, luego los factores o grupos, luego la base de datos de la que provienen. La naturaleza de la función no acepta operadores de pipa, por lo que debemos de realizar cada prueba por separado.
Para la prueba de Bartlett con enfoque a distribuciones paramétricas, se hace de la siguiente manera:
bartlett.test(hdl ~ sexo, data = BD2)
Bartlett test of homogeneity of variances
data: hdl by sexo
Bartlett's K-squared = 0.026622, df = 1, p-value = 0.8704
Notarás que es exactamente igual… Solo hay que cambiar el nombre de la función.
1.3 Pruebas de Comparación de Medias
1.3.1 Prueba t de una Muestra
Esta prueba compara la media de de una variable con un valor predeterminado, conocido o hipotético, se realiza de la siguiente manera:
t.test(BD2$glucosa, mu = 100)
One Sample t-test
data: BD2$glucosa
t = 2.5237, df = 402, p-value = 0.012
alternative hypothesis: true mean is not equal to 100
95 percent confidence interval:
101.4748 111.8701
sample estimates:
mean of x
106.6725
Como ya vimos, podemos agrupar nuestros datos a como lo necesitemos, y luego hacer la prueba estadística. Asumamos que queremos hacer la prueba de una muestra para dos subgrupos de la variable “diabetes_log”:
BD2 %>%
group_by(diabetes_log) %>%
summarise(
valor_p = t.test(glucosa, mu = 100)$p.value,
media = mean(glucosa, na.rm = TRUE),
n = n()
)# A tibble: 3 × 4
diabetes_log valor_p media n
<lgl> <dbl> <dbl> <int>
1 FALSE 1.48e-10 90.9 325
2 TRUE 3.12e-13 190. 65
3 NA 5.35e- 4 86.7 13
En este código sucede lo siguiente: - “valor_p = t.test(glucosa, mu = 100)$p.value”: creamos el objeto de “valor_p” que contiene solamente el resultado del valor de p de la prueba t de Student contra la media de 100. - “media = mean(glucosa, na.rm = TRUE)”: guardamos la media de la glucosa por grupo de nuestra base de datos. - “n = n()”: guardamos la n u observaciones.
Listo, nos entrega una cuadro muy visual en nuestra terminal.
1.3.2 Prueba de t de Muestras Independientes
Esta prueba estadística compara las medias de dos grupos que no están relacionados o pareados, se realiza de la siguiente manera:
t.test(glucosa ~ diabetes_log, data = BD2_R, var.equal = T)
Two Sample t-test
data: glucosa by diabetes_log
t = -18.499, df = 388, p-value < 2.2e-16
alternative hypothesis: true difference in means between group FALSE and group TRUE is not equal to 0
95 percent confidence interval:
-109.18499 -88.20578
sample estimates:
mean in group FALSE mean in group TRUE
90.88923 189.58462
t.test(glucosa ~ diabetes_log, data = BD2_R)
Welch Two Sample t-test
data: glucosa by diabetes_log
t = -9.9809, df = 66.547, p-value = 7.455e-15
alternative hypothesis: true difference in means between group FALSE and group TRUE is not equal to 0
95 percent confidence interval:
-118.43529 -78.95548
sample estimates:
mean in group FALSE mean in group TRUE
90.88923 189.58462
La primera línea hace la prueba t de Student, asumiendo las varianzas iguales, mientras que la segunda hace el test de Welch para varianzas no iguales.
La sintaxis es la siguiente: primero, llamamos a la función “t.test”, seleccionamos la variables numérica de la base de datos, usamos el símbolo “~”, seleccionamos la variable agrupadora, y seleccionamos si hay igualdad de varianzas ( T para igualdad, F para no igualdad).
1.3.3 Prueba de t de Muestras Pareadas
En esta prueba analizamos la diferencia de medias entre dos grupos que tengan datos pre y post, o que estén pareados (antes o después de un manejo, tratamiento, prueba, etc.).
Se hace la siguiente manera:
BD2 %>%
group_by(tx_ta) %>%
summarise(
dif_medias = mean(tas_1 - tas_2, na.rm = T),
valor_p = t.test(tas_1, tas_2, paired = T)$p.value,
n = n()
)# A tibble: 2 × 4
tx_ta dif_medias valor_p n
<lgl> <dbl> <dbl> <int>
1 FALSE 2.38 1.09e- 2 141
2 TRUE -13.4 2.42e-32 262
Ya que tenemos la variable de aquellos tomaron un manejo para TA, los podemos agrupar por esa variable, y luego llevamos a cabo la misma prueba que hicimos, pero anexamos el argumento “paired = T”.
1.3.4 Prueba de ANOVA
La prueba de ANOVA (Análisis de Varianza), básicamente es una extensión de la prueba de t que admite más de dos grupos. Se utiliza cuando en nuestra variable agrupadora tenemos tres o más niveles.
Se hace de la siguiente manera:
ANOVA_test <- aov(BD2$colesterol ~ BD2$act_fisica_fac)
summary(ANOVA_test) Df Sum Sq Mean Sq F value Pr(>F)
BD2$act_fisica_fac 2 16999 8500 4.504 0.0116 *
Residuals 387 730265 1887
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
13 observations deleted due to missingness
En el caso de ANOVA se debe crear el objeto y después se hace el resumen de los datos para obtener el valor de significancia. La sintaxis es igual que en el resto de las pruebas que hemos visto. Solo nos indica si hay diferencia en algún grupo, para conocer cuál debemos realizar pruebas post hoc.
Aquí no cambies el nombre del objeto “ANOVA_test”, ya que lo usaremos más adelante.
1.4 Prueba No Paramétricas
Entre las pruebas no paramétricas se puede seleccionar entre los siguientes supuestos:
- Dos grupos independientes: U de Mann-Whitney
- TA entre un grupo con manejo y otro grupo sin manejo
- Dos grupos dependientes o relacionados: Wilcoxon
- TA pre y post manejo en los mismos individuos
- Tres o más grupos independientes: Kruskal-Wallis
- Glucosas entre un grupo con manejo farmacológico, otro con solo dieta, y otro con ambos manejos
- Tres o más grupos dependientes o relacionados: Friedman
- Glucosas pre y post manejos: grupo con manejo farmacológico, grupo con manejo de dieta, grupo con manejo de dieta y farmacológico
1.4.1 Prueba de U de Mann-Whitney
Es exactamente igual que la prueba t.
wilcox.test(tas_1 ~ tx_ta, data = BD2_R)
Wilcoxon rank sum test with continuity correction
data: tas_1 by tx_ta
W = 32038, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0
Notemos que las pruebas pueden detectar niveles en formato lógico, por lo que se separa en los dos grupos y nos arroja el valor de significancia calculado.
1.4.2 Prueba de Wilcoxon
La prueba de Wilcoxon es la alternativa no paramétrica para la prueba t de muestras pareadas, se realiza de la siguiente manera:
wilcox.test(BD2$tas_1, BD2$tas_2, paired = T)
Wilcoxon signed rank test with continuity correction
data: BD2$tas_1 and BD2$tas_2
V = 15280, p-value < 2.2e-16
alternative hypothesis: true location shift is not equal to 0
Exactamente igual que “t.test”.
1.4.3 Prueba de Kruskal-Wallis
La prueba de Kruskal-Wallis es la alternativa no paramétrica para la prueba de ANOVA de grupos no pareados o independientes, se realiza de la siguiente manera:
kruskal.test(BD2$colesterol~BD2$lugar_origen)
Kruskal-Wallis rank sum test
data: BD2$colesterol by BD2$lugar_origen
Kruskal-Wallis chi-squared = 2.3246, df = 2, p-value = 0.3128
Y así, con cualquier variable que deseemos.
1.4.4 Prueba de Friedman
Es la alternativa no paramétrica de la prueba de ANOVA para grupos pareados. Aquí evaluamos tres o más grupos consecuentes o dependientes. Para ello, vamos a crear una pequeña base de datos:
datos_F <- data.frame(sujeto = rep(1:5, each=4),
medicamento = rep(c("A", "B", "C", "D"), times=5),
biomarcador = c(30, 28, 16, 34, 14, 18, 10, 22, 24, 20,
18, 30, 38, 34, 20, 44, 26, 28, 14, 30))
summary(datos_F) sujeto medicamento biomarcador
Min. :1 Length:20 Min. :10.0
1st Qu.:2 Class :character 1st Qu.:18.0
Median :3 Mode :character Median :25.0
Mean :3 Mean :24.9
3rd Qu.:4 3rd Qu.:30.0
Max. :5 Max. :44.0
Ahora, podemos proceder a la prueba:
friedman.test(y=datos_F$biomarcador,
groups=datos_F$medicamento,
blocks=datos_F$sujeto)
Friedman rank sum test
data: datos_F$biomarcador, datos_F$medicamento and datos_F$sujeto
Friedman chi-squared = 13.56, df = 3, p-value = 0.00357
La dificultad radica en la construcción de la base de datos. En primera instancia debe contener tres variables: la variable de datos a analizar (“y”), la variable de los niveles a agrupar (“groups”) y la variable de individuos o sujetos de estudio (“blocks”).
Naturalmente, los datos deben de estar equilibrados, debe de existir el mismo número de observaciones para cada sujeto y grupo, en este caso 4 valores por biomarcador por grupo y por sujeto, ya que cada sujeto tiene una medición del biomarcador por fármaco (A, B, C, D).
1.5 Pruebas de Proporciones
Las pruebas de proporción se dividen en tres:
- Comparación de frecuencias esperadas vs observadas: Chi-cuadrada (χ²)
- Comparación de frecuencias esperadas vs observadas si en una observación existe un valor menor de cinco o si el tamaño total de la muestra es menor de 20 o si hay una despropoción muy grande entre filas o columnas: Exacta de Fisher
- Comparación de proporciones entre dos grupos: Prueba Z
1.5.1 Prueba de Chi-cuadrada (χ²)
Lo primero que debemos de hacer es analizar las proporciones por grupos de las variables que queremos comparar, primero se hacen las tablas de contingencia:
table(
BD2$sexo,
BD2$diabetes_log
)
FALSE TRUE
hombre 133 29
mujer 192 36
Ya vemos la distribución de los datos que es proporcionado, no hay valores menores de cinco y la muestra es mayor de veinte.
chisq.test(
BD2$sexo,
BD2$diabetes_log
)
Pearson's Chi-squared test with Yates' continuity correction
data: BD2$sexo and BD2$diabetes_log
X-squared = 0.17105, df = 1, p-value = 0.6792
Y listo, no hay diferencia, así de simple es hacer las chi-cuadradas en R.
Podemos hacer la misma prueba con varios grupos, aquí no hay modificaciones:
table(
BD2$diabetes_log,
BD2$act_fisica_fac
)
Alto Bajo Sedentario
FALSE 93 150 73
TRUE 9 28 26
chisq.test(
BD2$diabetes_log,
BD2$act_fisica_fac
)
Pearson's Chi-squared test
data: BD2$diabetes_log and BD2$act_fisica_fac
X-squared = 11.217, df = 2, p-value = 0.003667
Y listo, podemos utilizar variables más de dos categorías sin problema.
1.5.2 Prueba Exacta de Fisher
Si se fallara en algún supuesto de los mencionados, procedemos a hacer exacta de Fisher. Sabemos de antemano que para el ejemplo previo lo más recomendado es la chi, pero por cuestiones de la base usaremos las mismas variables:
table(
BD2$diabetes_log,
BD2$act_fisica_fac
)
Alto Bajo Sedentario
FALSE 93 150 73
TRUE 9 28 26
fisher.test(
BD2$diabetes_log,
BD2$act_fisica_fac
)
Fisher's Exact Test for Count Data
data: BD2$diabetes_log and BD2$act_fisica_fac
p-value = 0.004095
alternative hypothesis: two.sided
Y listo, misma sintaxis, diferente función
1.5.3 Prueba Z de Dos Proporciones
Si quisiéramos comparar dos proporciones, primeramente debemos obtener las frecuencias en una tabla cruzada:
addmargins(table(BD2$diabetes_log,
BD2$sexo))
hombre mujer Sum
FALSE 133 192 325
TRUE 29 36 65
Sum 162 228 390
La función “addmargins” nos genera la suma de totales por cada fila y columna. La función “table” nos genera una tabla cruzada de las variables que solicitemos.
Con las frecuencias por grupo, fila y columna, podemos preguntarnos si las frecuencias de mujeres son iguales o diferentes dependiendo si tienen o no diabetes. Podemos llevarlo a cabo de la siguiente manera:
prop.test(x = c(192,36),
n = c(325,65))
2-sample test for equality of proportions with continuity correction
data: c(192, 36) out of c(325, 65)
X-squared = 0.17105, df = 1, p-value = 0.6792
alternative hypothesis: two.sided
95 percent confidence interval:
-0.1044480 0.1782942
sample estimates:
prop 1 prop 2
0.5907692 0.5538462
Y no, las frecuencias no presentan una diferencia estadísticamente significativa. Luego podemos hacer la comparación con las variables que deseemos.
1.6 Correlación
Los modelos de correlación permiten evaluar una relación entre dos variables. Si observamos una tendencia lineal, en el eje de las “x” significa que no hay relación, si observamos un aumento o disminución progresiva o puntual, significa que existe relación en algún punto, pero se torna lineal o inversa si nos extendemos en alguno de los ejes.
Veremos tres tipos de correlación:
- Pearson: opción paramétrica para dos variables numéricas.
- Spearman: opción no paramétrica, se puede emplear una variable ordinal.
- Kendall: opción para dos variables ordinales.
1.6.1 Correlación de Pearson
Bastante simple de llevar a cabo, pero debemos recordar que no podemos tener datos NA:
cor(
BD2$edad,
BD2$colesterol,
use = "complete.obs",
method = "pearson"
)[1] 0.2331191
Recordemos que este es el método para calcular el grado de correlación.
1.6.2 Correlación de Spearman
Igual de simple de llevar a cabo:
cor(
BD2$diabetes_log,
BD2$glucosa,
use = "complete.obs",
method = "spearman"
)[1] 0.5325384
Recordemos que debemos tener valores numéricos para las correlaciones, por lo que tendríamos que llevar a cabo la transformación de variables.
1.6.3 Correlación de Kendall
Es correcto, es muy simple de llevar a cabo. El único inconveniente es que los niveles deben ser numéricos, o al menos lógicos. Además, recordemos que deben ser ordinales:
BD3 <- BD2 %>%
drop_na() %>%
mutate(
act_fisica_fac = case_when(
act_fisica_fac == "Sedentario" ~ 0,
act_fisica_fac == "Bajo" ~ 1,
act_fisica_fac == "Alto" ~ 2,
)
)
cor(
BD3$act_fisica_fac,
BD3$hdl,
method = "kendall"
)[1] 0.1922452
En este caso, tenemos que crear una nueva base que primeramente no tenga datos omitidos. Luego transformamos la variable de interés, “act_fisica_fac” con los valores de 0 para la base, que es “Sedentario” y vamos adicionando los niveles. Para esto, hacemos uso de la función “case_when”, que nos permite hacer una acción sí se encuentra determinada característica. Finalmente, corremos el modelo de correlación con el método de “kendall”.
1.7 Modelos de Regresión
Los modelos de regresión nos permiten identificar la relación entre dos o más variables, cuál o cuáles tienen mayor relevancia en una variable de interés u objetivo o dependiente, además de estimar los incrementos esperados para la variable dependiente acorde a la o las independientes (es decir, que tanto debería incrementarse o disminuirse la variable dependiente, si incrementamos la o las independientes).
Por fines de tiempo, solo se darán los primeros pasos
Veremos cuatro tipos de regresión:
- Regresión Lineal Simple: relación entre una variable dependiente continua y una variable independiente continua.
- Regresión Lineal Múltiple: relación entre una variable dependiente continua y múltiples variables independientes
- Regresión Logística: relación entre una variable dependiente binaria y una o más variables independientes.
- Regresión Logística Multinomial: relación entre una variable dependiente multifactorial y una o más variables independientes.
El modelo de Regresión Logística Multinomial se llevará a cabo con el archivo “BD_ML.qmd”, que se envió por aparte.
1.7.1 Regresión Lineal Simple
Para este tipo de modelo, vamos a crear unas variables de interés mediante código:
set.seed(1)
edad <- 30:80
APE <- .1 * edad + rnorm(50, mean = 0, sd = 1)Warning in 0.1 * edad + rnorm(50, mean = 0, sd = 1): longer object length is
not a multiple of shorter object length
El código se interpreta así: “set.seed” es una semilla de aleatorización, se agrega un número para que los valores aleatorios que vayamos a generar sean tan similares que se pueda reproducir el resultado. Creamos la variable edad, que va de 30 a 80, asumamos que son años. Creamos la variable APE (Antígeno Prostático Específico), que es una variable aleatoria y calculada; multiplicamos .1 por la edad, y sumamos una distribución normal que incluya 50 datos, con una media de cero y una desviación estándar de 1. Lo anterior genera 50 datos aleatorios que tienen cierta relación con la edad, pero hay variabilidad.
El siguiente paso es crear un gráfico para evaluar si nuestros datos siguen una distribución lineal:
plot(edad, APE, main = "Relación entre Edad y APE",
xlab = "Edad (años)", ylab = "APE (ng/ml)")
abline(lm(APE ~ edad), col = "red")
La función de “abline” agrega una línea a través de los puntos y queremos que esté basada en un modelo lineal (“lm”) ajustado a nuestras variables de interés.
Ahora, tenemos que crear un objeto que contenga nuestro modelo y solicitamos un resumen:
RLS <- lm(APE ~ edad)
summary(RLS)
Call:
lm(formula = APE ~ edad)
Residuals:
Min 1Q Median 3Q Max
-2.32775 -0.46734 -0.01834 0.63033 1.45985
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.209287 0.453374 0.462 0.646
edad 0.097762 0.007963 12.277 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.8371 on 49 degrees of freedom
Multiple R-squared: 0.7547, Adjusted R-squared: 0.7497
F-statistic: 150.7 on 1 and 49 DF, p-value: < 2.2e-16
Y listo, obtenemos nuestro modelo de regresión lineal, donde vemos el intercepto, el coeficiente para la edad, la significancia estadística, y los valores de los cuadrados.
1.7.2 Regresión Lineal Múltiple
En este caso, debemos de tener dos o más variables independientes de tipo numérico, asumamos que todas nuestras variables presentan un relación lineal, y creemos el modelo.
set.seed(5)
n <- 50
min_inactividad <- rpois(n, lambda = 60)
calorias <- rpois(n, lambda = 2000)
peso <- rnorm(n, mean = 70, sd = 10)
glucosa <- 80 + 0.3 * min_inactividad - 0.05 * calorias + 1.5 * peso + rnorm(n, mean = 0, sd = 10) Estas son las variables, meramente inventadas. La función “rpois” genera una distribución de poisson.
modelo_glucosa <- lm(glucosa ~ min_inactividad + calorias + peso)
summary(modelo_glucosa)
Call:
lm(formula = glucosa ~ min_inactividad + calorias + peso)
Residuals:
Min 1Q Median 3Q Max
-26.4765 -7.3672 0.1089 7.6880 18.2869
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -56.84471 82.68038 -0.688 0.495
min_inactividad 0.22717 0.20216 1.124 0.267
calorias 0.02456 0.04135 0.594 0.556
peso 1.38746 0.14600 9.503 2e-12 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 10.2 on 46 degrees of freedom
Multiple R-squared: 0.6855, Adjusted R-squared: 0.665
F-statistic: 33.43 on 3 and 46 DF, p-value: 1.279e-11
Y listo, obtenemos los mismos estadísticos pero esta vez por cada variable independiente. Cabe mencionar que primeramente debemos poner nuestra variable dependiente, símbolo de virgulilla, y cada variable independiente que deseemos agregar con un signo de “+”.
1.7.3 Regresión Logística Binomial
La regresión logística nos permite crear un modelo entre una variable dependiente binaria y dos o más variables independientes. Hagamos un modelo para intentar predecir si nuestras variables pueden ser útiles para predecir epoc:
BD_glm <- BD2
colnames(BD_glm) [1] "id" "colesterol" "glucosa" "hdl"
[5] "col_hdl_ratio" "hb1ac" "diabetes_log" "lugar_origen"
[9] "edad" "sexo" "altura" "peso"
[13] "imc" "act_fisica_fac" "tx_ta" "tas_1"
[17] "tad_1" "tas_2" "tad_2" "cintura"
[21] "cadera"
Vemos las variables de interés, ahora vamos a crear el modelo:
modelo <- glm(diabetes_log ~
col_hdl_ratio +
edad +
imc +
act_fisica_fac +
cintura +
cadera,
data = BD_glm,
family = binomial)
summary(modelo)
Call:
glm(formula = diabetes_log ~ col_hdl_ratio + edad + imc + act_fisica_fac +
cintura + cadera, family = binomial, data = BD_glm)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -9.160934 1.607063 -5.700 1.20e-08 ***
col_hdl_ratio 0.363060 0.094980 3.822 0.000132 ***
edad 0.050585 0.010839 4.667 3.06e-06 ***
imc -0.018085 0.031703 -0.570 0.568368
act_fisica_facBajo -0.066731 0.456539 -0.146 0.883790
act_fisica_facSedentario 0.025417 0.503819 0.050 0.959764
cintura 0.028049 0.021106 1.329 0.183863
cadera 0.008449 0.020049 0.421 0.673460
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 335.22 on 371 degrees of freedom
Residual deviance: 268.10 on 364 degrees of freedom
(31 observations deleted due to missingness)
AIC: 284.1
Number of Fisher Scoring iterations: 5
La sintaxis es exactamente igual que en la regresión lineal, solamente cambia la función por “glm” y el argumento “family” con la opción de “binomial”.
Con eso se crea el modelo, y lo visualizamos con “summary”.
Naturalmente, algo que es bastante empleado, es obtener los OR para cada variable predictora, esto asumiendo que presentaron OR significativos.
OR_modelo <- exp(coef(modelo))
OR_modelo (Intercept) col_hdl_ratio edad
0.0001050647 1.4377224851 1.0518859087
imc act_fisica_facBajo act_fisica_facSedentario
0.9820772213 0.9354469981 1.0257432507
cintura cadera
1.0284462851 1.0084845391
Naturalmente, puede que solo queramos los significativos, te dejo el siguiente código para hacerlo más fácil:
OR_modelo <- exp(coef(modelo))
valores_p <- summary(modelo)$coefficients[, "Pr(>|z|)"]
OR_p_sig <- OR_modelo[valores_p < 0.05 & names(OR_modelo) != "(Intercept)"]
OR_p_sigcol_hdl_ratio edad
1.437722 1.051886
1.8 Pruebas Post-Hoc
Se usan posterior a un ANOVA positivo (si se encontraron diferencias) y permiten identificar cuáles grupos específicos presentan la diferencia.
Existen diversas pruebas post hoc, sin embargo, las más empleadas son:
- Tukey
- Bonferroni
- Scheffé
1.8.1 Prueba de Tukey
Es útil cuando se tiene equilibrio entre grupos, se realiza de la siguiente manera:
TukeyHSD(ANOVA_test) Tukey multiple comparisons of means
95% family-wise confidence level
Fit: aov(formula = BD2$colesterol ~ BD2$act_fisica_fac)
$`BD2$act_fisica_fac`
diff lwr upr p adj
Bajo-Alto 16.042898 3.465897 28.619898 0.0080425
Sedentario-Alto 10.504854 -3.736787 24.746496 0.1933351
Sedentario-Bajo -5.538043 -18.115044 7.038957 0.5545997
La ventaja de dicha prueba, es que nos otorga la diferencia entre grupos (diff), los intervalos de confianza inferior (lwr) y superior (upr), y el valor de p. Con lo anterior constatamos (aún más…), de que no hay diferencia entre las edad de los grupos. Si en la prueba de ANOVA hubiera resultado positiva, aquí sabríamos cuál.
1.8.2 Prueba de Bonferroni
Útil para pequeños grupos, ya que se ajusta al número de comparaciones, pero es más estricto, lo que genera resultados significativos más certeros. Se hace de la siguiente manera:
pairwise.t.test(BD2$edad, BD2$act_fisica_fac, p.adjust.method = "bonferroni")
Pairwise comparisons using t tests with pooled SD
data: BD2$edad and BD2$act_fisica_fac
Alto Bajo
Bajo 0.20206 -
Sedentario 3.7e-06 0.00065
P value adjustment method: bonferroni
Y nos arroja los resultados en una tabla cruzada con los valores de p.
1.8.3 Prueba de Scheffé
Es útil cuando se observan grupos desiguales. Se hace de la siguiente forma:
pacman::p_load(DescTools)
ScheffeTest(ANOVA_test)
Posthoc multiple comparisons of means: Scheffe Test
95% family-wise confidence level
$`BD2$act_fisica_fac`
diff lwr.ci upr.ci pval
Bajo-Alto 16.042898 2.907358 29.178437 0.0117 *
Sedentario-Alto 10.504854 -4.369252 25.378960 0.2231
Sedentario-Bajo -5.538043 -18.673583 7.597496 0.5851
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Y al igual que con Tukey, nos otorga la diferencia, IC y valores de p.