Introducción a la estadística descriptiva e inferencia

Cuadernos prácticos del Máster de Bioinformática (curso 2024-2025)

Author

Javier Álvarez Liébana

1 Estadística descriptiva univariante

La estadística descriptiva es una rama de la estadística que se dedica a recolectar, organizar, presentar y analizar un conjunto de datos para describir las características y comportamientos de dicho conjunto.

Además de para conocer y entender los datos es la fase en la que detectaremos errores e incongruencias, teniendo muchas veces que hacer una depuración de datos para dejar la base de datos preparada para su análisis.

1.1 Etapas

1.1.1 Fase 1: recolección

La podemos hacer a través de encuestas, experimentos, observaciones, registros, etc. Lo más importante en esta etapa es que los datos sean representativos del fenómeno o población que se estudia.

Ejemplo: queremos llevar a cabo una investigación para analizar la satisfacción de los pacientes con los servicios de urgencias de la red de hospitales públicos madrileños. ¿Qué muestra será más representativa?

  1. Los 100 primeros pacientes que lleguen a las urgencias del Hospital 12 de Octubre.

  2. Los 10 primeros pacientes que lleguen a las urgencias de todos los hospitales de la red de hospitales madrileños.

  3. Seleccionamos al azar 3 hospitales del grupo 3 (hospitales de gran complejidad), grupo 2 (hospitales de complejidad intermedia) y grupo 3 (hospitales de baja complejidad) y de cada uno de ellos seleccionamos un número proporcional de pacientes según el número total de pacientes que llegan a cada hospital.

Solución:

  1. Seleccionamos al azar 3 hospitales del grupo 3 (hospitales de gran complejidad), grupo 2 (hospitales de complejidad intermedia) y grupo 3 (hospitales de baja complejidad) y de cada uno de ellos seleccionamos un número proporcional de pacientes según el número total de pacientes que llegan a cada hospital.

Con a) todas las conclusiones que saquemos del estudio serán aplicadas al Hospital 12 de Octubre. Con b) es una forma semi representativa pero válida de conseguir una muestra de forma fácil. La rama de la estadística que se dedica a estudiar esta parte del análisis se conoce como muestreo

1.1.2 Fase 2: organización y presentación

Una vez recopilados los datos deben organizarse de manera que sean comprensibles y manejables. Para ello necesitaremos clasificar los datos en cuantitativos y cualitativos y estudiar sus características según su tipo.

  • Messy data: datos mal organizados o desordenados (múltiples individuos en cada fila, misma variable pero separada en varias columnas, etc).

  • Tidy data: datos organizados y estandarizados (una variable en cada columna, un registro/individuo en cada fila y un solo valor en cada celda).

La información la poder resumir o presentar de distintas maneras.

  • Estadísticos o medidas:

    • Medidas cualitativas: tablas de frecuencias.

    • Medidas cuantitativas: medidas numéricas de centralización y dispersión.

  • Gráficamente:

    • Medidas cualitativas: gráficos de barras, gofres, etc.

    • Medidas cuantitativas: histogramas, densidades, boxplots, etc

1.1.3 Fase 3: relación entre variables

Una vez hecho el estudio de cada variable por separado buscaremos relacionar dos variables de forma simultánea para buscar la asociación entre ellas:

  • Cuali vs cuali: tablas de frecuencias –> pruebas de Fisher y chi-cuadrado –> interpretación de OR y RR.

  • Cuanti vs cuanti: correlación –> test de correlaciones (o test de igualdad de distribuciones) –> diagrmas de dispersión.

  • Cuanti vs cuali: ANOVA, biserial correlation, etc.

1.2 Conceptos básicos

En estadística es fundamental entender los conceptos de población, muestra y variable, ya que son la base para cualquier análisis estadístico.

  • Población

La población es el conjunto completo de elementos o individuos que tienen una característica común y sobre los cuales se desea obtener información. En la mayoría de casos el acceso a la totalidad de la población es inviable por motivos económicos, legales o éticos, así que en la mayoría de situaciones las conclusiones deberemos sacarlas haciendo uso de lo que se conoce como muestra.

Ejemplo: la diferencia entre censo y encuesta es que el primero recopila datos de todos los individuos de una población, mientras que el segundo trata de estimarlos o inferirlos a partir de una muestra representativa de la misma.

  • Muestra

Una muestra es un subconjunto de la población que se selecciona para su análisis con el fin de hacer inferencias o generalizaciones sobre la población completa. La muestra debe ser representativa de la población para que las conclusiones sean válidas.

1.2.1 Tipos de muestreo

  • Muestreo aleatorio simple: cada miembro de la población tiene la misma probabilidad de ser seleccionado.

  • Muestreo estratificado: la población se divide en subgrupos (estratos) y se toma una muestra de cada uno.

  • Muestreo (no aleatorio) sistemático: se selecciona cada n-ésimo miembro de la población.

  • Muestreo (no aleatorio) por cuotas: se seleccionan aquellos individuos que cumplan ciertas condiciones.

  • Muestreo por conveniencia: se elige a los miembros que son más fáciles de acceder, aunque este método puede introducir sesgos.

 

Veamos algunos ejemplos:

  • Ejemplo 1

    • Población: todos los pacientes que han sido atendidos en un hospital específico durante el último año.

    • Muestra (aleatoria simple): Seleccionamosseleccionamos 200 pacientes de manera aleatoria del registro de pacientes del último año. Para asegurarnos de que la muestra sea representativa, podemos usar muestreo aleatorio simple, donde cada paciente tiene la misma probabilidad de ser seleccionado.

  • Ejemplo 2

    • Población: todos los estudiantes matriculados en una universidad durante el semestre actual.

    • Muestra (aleatoria estratificada): seleccionamos 500 estudiantes utilizando muestreo estratificado para asegurar que diferentes subgrupos (estratos) de la población estén representados. Los estratos pueden ser facultades (mismo % de facultades representadas que en la población universitaria), género, clase social, etc.

  • Ejemplo 3

    • Población: todas las especies de árboles en un bosque determinado.

    • Muestra (sistemática no aleatoria): Sseleccionamos parcelas de muestreo de 10m x 10m dentro del bosque y contabilizamos todas las especies de árboles presentes en esas parcelas. Esto se puede hacer utilizando muestreo sistemático.

  • Ejemplo 4

    • Población: todos los pacientes de covid de un hospital.

    • Muestra (por cuotas no aleatoria): seleccionamos solo a las personas mayores de 65 años para realizar un estudio clínico inicial sobre los efectos secundarios de una posible vacuna de la covid-19.

Estos métodos aseguran, de una manera u otra, que las muestras sean representativas de sus respectivas poblaciones, lo que permite realizar análisis precisos y confiables.

1.2.2 Tipos de variables

Una variable es cualquier característica o atributo que puede tomar diferentes valores entre los individuos de la población o muestra. Las variables pueden ser de varios tipos según su naturaleza:

  • Cualitativas (o categóricas): describen cualidades o categorías. Ejemplos:

    • Nominales: no tienen un orden intrínseco (e.g., género, estado civil).
    • Ordinales: tienen un orden intrínseco (e.g., niveles de satisfacción, grado académico, sano-leve-grave).
  • Cuantitativas: describen cantidades y pueden ser medidas numéricamente. Ejemplos:

    • Discretas finitas: toman valores finitos (e.g., número de hijos, número de visitas al médico, escala de dolor).
    • Discretas infinitas: toman valores infinitos (o que se podrían considerar como tal) pero podemos enumerarlas y sabemos siempre el siguiente elemento (e.g., número de pelos de nuestra cabellera, número de personas que pueden entrar en una tienda en un periodo dado).
    • Continuas: pueden tomar cualquier valor dentro de un rango (e.g., altura, peso, tiempo de espera).
  • Modalidades

Una modalidad es uno de los valores que toma una variable dentro de una muestra.

El conjunto de modalidades posibles que podría haber tomado (en tu población) se suele conocer también como soporte. Algunos ejemplos en función del tipo de variables son:

  • Color de ojos (cualitativa nominal): negro, azul y marrón (3 modalidades en esa muestra de un espectro de colores más amplio que podríamos tener como soporte).
  • Estado del paciente (cualitativa ordinal): sano, leve y grave (3 modalidades en esa muestra de un conjunto de opciones - por ejemplo, sano, leve, grave, UCI, fallecido - que podríamos tener).

Una modalidad es uno de los valores que toma una variable dentro de una muestra. El conjunto de modalidades posibles que podría haber tomado (en tu población) se suele conocer también como soporte. Algunos ejemplos en función del tipo de variables son:

  • Número de hijos (cuantitativa discreta finita): 0, 1, 2 y 3 (4 modalidades en esa muestra de un conjunto de valores posibles - de 0 a…20 hijos - que podríamos tener en la población general).

  • Temperatura anual de Madrid (cuantitativa continua): un rango de -5ºC a 45ºC (un rango continuo de valores en los que se mueve nuestra variable en la muestra (de un rango más amplio, por ejemplo desde -20ºC a 50ºC que podría moverse de manera global si tuviésemos otra muestra).

Veamos algunos ejemplos: piensa en tipos de variables que se pueden medir en cada uno de los ejemplos de población y muestra que hemos estudiado.

  • Ejemplo 1
Población Muestra Variables
Todos los pacientes de un hospital de los queremos estudiar su grado de satisfcacción con la atención que han recibido 200 pacientes seleccionados de forma aleatoria del registro de pacientes en el último año Cuantitativas: Cualitativas:
  • Ejemplo 1: solución
Población Muestra Variables
Todos los pacientes de un hospital de los queremos estudiar su grado de satisfcacción con la atención que han recibido 200 pacientes seleccionados de forma aleatoria del registro de pacientes en el último año Cuantitativas: edad (discreta), tiempo de espera (continua), grado de satisfacción en una escala del 0 al 10 (discreta), número de visitas en el último año (discreta). | Cualitativas: género (nominal), estado civil (nominal), si viene acompañado (nominal), grado de satisfacción como bueno, regular malo (ordinal).
  • Ejemplo 2
Población | Muestra | Variables
  • Ejemplo 2: solución
Población Muestra Variables
Todos los estudiantes matriculados en una universidad de los que queremos estudiar las calificaciones obtenidas 500 estudiantes de las diferentes facultades Cuantitativas: calificaciones, edad (discreta), número de veces que se ha presentado al examen (discreta). Cualitativas: asignaturas (nominal), facultad (nominal).
  • Ejemplo 3
Población | Muestra | Variables
  • Ejemplo 3: solución
Población Muestra Variables
Especies de árboles en un bosque de los que queremos estudiar su estado de salud Selección sistemática de parcelas de 10m x 10m dentro del bosque Cuantitativas: altura del árbol (continua), diámetro del árbol (continua), edad del árbol (discreta). Cualitativas: especie del árbol (nominal), estado de salud (ordinal), tipo de suelo (nominal).

1.3 Características numéricas

Nos referimos a las medidas con las que se pretende resumir y condensar la información contenida en un conjunto de datos. Las mayoría de características numéricas las mediremos en variables cuantitativas.

1.3.1 Medidas de centralización

Son los valores que resumen el conjunto de los datos de forma que reflejan el centro de la distribución de la tabla de frecuencias

1.3.1.1 Media

Es el valor medio o centro de gravedad (el valor más cercano a todos los puntos a la vez). Es la suma de todos los valores dividida por el número total de valores.

\[\bar x= \frac{\sum^n_{i=1} x_i}{n}\]

  • Ejemplo 1

A los enfermeros de un centro de salud se les pregunta por el nº de hijos que tienen. Sus respuestas son 0,1,2,0,1,1,0,0,2,2,3. ¿Cuál es su media?

\(n=11\)

\(\sum^n_{i=1} x_i = 0+1+2+0+1+1+0+0+2+2+3 = 12\)

\(\bar x= \frac{\sum^n_{i=1} x_i}{n} = \frac{12}{11} = 1.09\) hijos

x <- c(0, 1, 2, 0, 1, 1, 0, 0, 2, 2, 3)
mean(x)
[1] 1.090909
  • Ejemplo 2

A los enfermeros de un centro de salud se les pregunta por el nº de hijos que tienen. Sus respuestas son 0,1,2,0,1,1,0,0,2,2,3,10. ¿Cuál es su media?

\(\bar x= \frac{\sum^n_{i=1} x_i}{n} = \frac{22}{12} = 1.83\) hijos

x <- c(0, 1, 2, 0, 1, 1, 0, 0, 2, 2, 3, 10)
mean(x)
[1] 1.833333
Cuidado…

La media es una medida útil y ampliamente aplicada de la tendencia central, pero debe ser utilizada con precaución en conjuntos de datos que contienen valores atípicos o están distribuidos de manera asimétrica.

1.3.1.2 Mediana

Es el valor del medio SIEMPRE Y CUANDO ordenemos los datos. Divide la distribución de frecuencias en dos partes.

Para calcularla debemos realizar los siguientes pasos:

  1. Ordenar los datos en orden creciente

  2. Según el número de observaciones (n):

    • Si n es impar: La mediana es el valor que ocupa la posición central

    • Si n es par: La mediana es el promedio de los dos valores central

  • Ejemplo 1: variables cuantitativas (número impar)

  • Datos: 3, 1, 4, 2, 5 (n=5)

  • Ordenados: 1, 2, 3, 4, 5

  • Mediana: 3 (el tercer valor)

  • Ejemplo 2: variables cuantitativas (número par)

  • Datos: 7, 2, 4, 6 (n=4)

  • Ordenados: 2, 4, 6, 7

  • Mediana: (4 + 6) / 2 = 5

  • Ejemplo 3: variables cualitativas (ordinales)

  • Datos: “notable”, “suspenso”, “sobresaliente”, “suspenso”, “notable”, “aprobado”, “notable” (n=7).

  • Ordenados: “suspenso”, “suspenso”, “aprobado”, “notable”, “notable”, “notable”, “sobresaliente”.

  • Mediana: “notable”.

Consejo

La mediana es especialmente útil en distribuciones asimétricas o cuando se quiere una medida de tendencia central que no sea afectada por valores extremadamente altos o bajos.

  • Ejemplo 4:

A los enfermeros de un centro de salud se les pregunta por el nº de hijos que tienen. Sus respuestas son 0,1,2,0,1,1,0,0,2,2,3. ¿Cuál es su mediana?

\(n=11\)

Ordenados: 0,0,0,0,1,1,1,2,2,2,3

Mediana: Posición 6 = 1 hijo

x <- c(0,1,2,0,1,1,0,0,2,2,3)

median(x)
[1] 1
  • Ejemplo 5:

A los enfermeros de un centro de salud se les pregunta por el nº de hijos que tienen. Sus respuestas son 0,1,2,0,1,1,0,0,2,2,3,10. ¿Cuál es su mediana?

\(n=12\)

Ordenados: 0,0,0,0,1,1,1,2,2,2,3,10

Mediana: Posición 6 y 7 = 1 +1 /2 = 1 hijo

x <- c(0,1,2,0,1,1,0,0,2,2,3, 10)

median(x)
[1] 1
1.3.1.3 Moda

Es el valor que presenta la máxima frecuencia y se puede calcular para todas las variables (también) cualitativas. Es más, es un valor que suele usarse en el análisis de variables cualitativas.

  1. Unimodal:

    • Datos: “negro”, “negro”, “amarillo”, “verde”, “amarillo”, “negro”
    • Moda: “negro” (aparece 3 veces, más que cualquier otro valor)
  2. Bimodal:

    • Datos: 1, 2, 3, 3, 4, 4, 5
    • Modas: 3 y 4 (ambos aparecen dos veces)
  3. Multimodal:

    • Datos: 2, 2, 3, 3, 4, 4, 5, 5
    • Modas: 2, 3, 4, y 5 (todos aparecen dos veces)
  4. Sin moda:

    • Datos: 1, 2, 3, 4, 5
    • Moda: No hay moda (todos los valores aparecen solo una vez)
  • Ejemplo 1:

A los enfermeros de un centro de salud se les pregunta por el nº de hijos que tienen. Sus respuestas son 0,1,2,0,1,1,0,0,2,2,3. ¿Cuál es su moda?

Code
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Code
datos <- tibble("x" = c(0,1,2,0,1,1,0,0,2,2,3))

datos |>
  count(x)
# A tibble: 4 × 2
      x     n
  <dbl> <int>
1     0     4
2     1     3
3     2     3
4     3     1

La modalidad más frecuente es 0 por lo que la moda es 0.

1.3.2 Medidas de posición: cuantiles

Los cuantiles son valores que dividen un conjunto de datos en partes iguales según la distribución de los datos (de nuevo asumiento que tenemos los datos ordenados de menor a mayor). Los cuantiles son útiles para comprender la distribución y la dispersión de los datos. Existen diferentes tipos de cuantiles, cada uno con un número específico de divisiones:

  1. Cuartiles: dividen el conjunto de datos en cuatro partes iguales.

    • Primer cuartil (Q1): divide el 25% inferior de los datos del 75% superior.

    • Mediana (Q2): divide el 50% inferior del 50% superior. Es el segundo cuartil.

    • Tercer cuartil (Q3): divide el 75% inferior del 25% superior.

  2. Deciles: dividen el conjunto de datos en diez partes iguales.

    • Primer decil (D1): divide el 10% inferior del 90% superior.

    • Segundo decil (D2): divide el 20% inferior del 80% superior.

    • Y así sucesivamente hasta el noveno decil (D9), que divide el 90% inferior del 10% superior.

  3. Percentiles: dividen el conjunto de datos en cien partes iguales.

    • Percentil 1 (P1): divide el 1% inferior del 99% superior.

    • Percentil 2 (P2): divide el 2% inferior del 98% superior.

    • Y así sucesivamente hasta el percentil 99 (P99), que divide el 99% inferior del 1% superior.

  • Ejemplo 1:

Supongamos que tenemos el siguiente conjunto de datos (que podemos ordenar): 10, 25, 4, 2, 14, 6, 18, 16, 8, 12, 20. ¿Cuáles son sus cuartiles?

Code
datos <- tibble("x" = c(10, 25, 4, 2, 14, 6, 18, 16, 8, 12, 20))

datos |> 
  reframe("cuartiles" = quantile(x))
# A tibble: 5 × 1
  cuartiles
      <dbl>
1         2
2         7
3        12
4        17
5        25

1.3.3 Medidas de dispersión

Medidas (solo disponibles para cuantitativas) que nos indican cómo de lejos o cerca están las observaciones del valor central que hemos calculado, es decir cuánto se alejan de la media o mediana: nos indican el grado de dispersión de la distribución de frecuencias.

1.3.3.1 Recorrido o rango

Indica la diferencia entre el valor máximo y el valor mínimo en un conjunto de datos.

  • Ejemplo 1

A los enfermeros de un centro de salud se les pregunta por el nº de hijos que tienen. Sus respuestas son 0,1,2,0,1,1,0,0,2,2,3. ¿Cuál es su recorrido?

  • Valor máximo = 3

  • Valor mínimo = 0

  • Recorrido= 3-0 = 3

x <- c(0,1,2,0,1,1,0,0,2,2,3)
max(x)- min(x)
[1] 3
  • Ejemplo 2

A los enfermeros de un centro de salud se les pregunta por el nº de hijos que tienen. Sus respuestas son 0,1,2,0,1,1,0,0,2,2,3,10. ¿Cuál es su recorrido?

  • Valor máximo = 10

  • Valor mínimo = 0

  • Recorrido= 10-0 = 10

x <- c(0,1,2,0,1,1,0,0,2,2,3, 10)
max(x) - min(x)
[1] 10
Cuidado…

El recorrido es útil cuando se necesita una medida rápida y simple de la dispersión, pero para análisis más detallados y robustos, se utilizan otras medidas de dispersión como la desviación estándar, la varianza o el rango intercuartílico.

1.3.3.2 Rango Intercuatílico (IQR)

Mide la amplitud del 50% central de un conjunto de datos. Se calcula como la diferencia entre el tercer cuartil (Q3) y el primer cuartil (Q1), proporcionando una medida robusta de la variabilidad de los datos al no ser afectada por valores atípicos o extremos.

\[IQR = Q_3 - Q_1\]

1.3.3.3 Varianza

Cuantifica cuánto varían los datos respecto a la media del conjunto. Una varianza alta indica que los datos están más dispersos alrededor de la media, mientras que una varianza baja indica que los datos están más agrupados cerca de la media. Importante: medimos las desviaciones al cuadrado para que no se cancelen signos.

\[s^2 = \frac{\sum_{i=1}^n (x_i - \bar x)^2}{n-1}\]

  • \(x_i\) representa cada valor individual en el conjunto de datos.

  • \(\bar x\) es la media de la muestra.

  • \(n\) es el tamaño de la muestra.

1.3.3.4 Desviación típica

Es la raíz cuadrada de la varianza y se calcula de la siguiente manera:

\[s = \sqrt {s^2} = \sqrt {\frac{\sum_{i=1}^n (x_i - \bar x)^2}{n-1}}\]

La desviación estándar se interpreta en las mismas unidades que los datos originales, lo que la hace más intuitiva que la varianza. Indica la dispersión promedio de los datos respecto a la media. Fíjate que en las medidas de dispersión el promedio lo estamos realizando diviendo entre n-1 y no entre n. Esto es debido a que los parámetros que hemos visto hasta ahora se conocen con un apellido: parámetros muestrales (calculados con los datos disponibles en una muestra).

El objetivo con ellos es aproximar los verdaderos parámetros poblacionales (la media real de la población, no la que calculas con tu tabla), y el mejor estimador posible de la varianza población (se conoce como estimador insesgado, sin sesgo) es la que hemos definido dividiendo entre n-1, de ahí que todos los softwares estadísticos nos calculen dicho valor (se la conoce también como cuasivarianza).

  • Ejemplo 1

A los enfermeros de un centro de salud se les pregunta por el nº de hijos que tienen. Sus respuestas son 0,1,2,0,1,1,0,0,2,2,3. ¿Cuál es su varianza y desviación típica?

x <- c(0,1,2,0,1,1,0,0,2,2,3)

var(x)
[1] 1.090909
sd(x)
[1] 1.044466
  • Ejemplo 2

A los enfermeros de un centro de salud se les pregunta por el nº de hijos que tienen. Sus respuestas son 0,1,2,0,1,1,0,0,2,2,3,10. ¿Cuál es su varianza y desviación típica?

x <- c(0,1,2,0,1,1,0,0,2,2,3, 10)

var(x)
[1] 7.606061
sd(x)
[1] 2.757909
1.3.3.5 Coeficiente de variación

Uno de los problemas al comparar dispersiones de dos variables diferentes es que tanto la varianza como la desviación típica dependen de la escala de los datos.

Esto implica que una desviación de, por ejemplo, 0.5, puede representar una dispersión pequeña (si el rango de mis datos está entre 100 y 200, por ejemplo) pero puede representar una dispersión enorme si el rango de mis datos es también pequeño (por ejemplo, datos entre 0 y 1).

Para poder comparar dispersiones de variables de diferentes rangos (o incluso unidades) existe el conocido como coeficiente de variación (CV):

\[CV = \frac s {|\bar x|}\]

El coeficiente de variación es siempre adimensional y positivo.

1.4 Tablas de frecuencias

Las variables cualitativas o cuantitativas discretas las vamos a poder resumir en tablas de frecuencias o de contigencia donde se ordenan y estructuran los valores de una variable x de forma resumida de la siguiente manera:

  • Frecuencia absoluta de x: nº de veces que se repite cada modalidad de x.

  • Frecuencia relativa de x: proporción de veces que se repite cada modalidad de x.

  • Frecuencia absoluta acumulada de x: nº de observaciones menores o iguales que cada modalidad de x (solo apto para cuantitativas o cualitativas ordinales ya que necesitamos una estructura de orden).

  • Frecuencia relativa acumulada de x: proporción de valores menores o iguales que cada modalidad de x (solo apto para cuantitativas o cualitativas ordinales ya que necesitamos una estructura de orden).

Valores de la variable Frecuecias Absolutas Frecuencias relativas Frecuencias Absolutas acumuladas Frecuencias Relativas acumuladas
\(x_i\) \(f_i\) \(p_i\) \(F_i\) \(P_i\)

1.4.1 Ejemplo 1

En un estudio sobre el grupo sanguíneo realizado con \(n = 6313\) individuos se obtuvo la siguiente tabla de frecuencias La variable tiene \(k = 4\) modalidades (O, A, B, AB).

Valores de la variable Frecuecias Absolutas Frecuencias relativas Frecuencias Absolutas acumuladas Frecuencias Relativas acumuladas
\(x_i\) \(f_i\) \(p_i\) \(F_i\) \(P_i\)
O 2892 2892/6313 = 0.458 2892 0.458
A 2625 1625/6313 = 0.416 5517 0.874
B 570 570/6313 = 0.09 6087 0.964
AB 226 226/6313 = 0.036 6313 1
TOTAL 6313 1 6313 1

\[\sum^k_{i=1} f_i=n\] \[\sum^k_{i=1} p_i = 1\]

¿Qué conclusiones sacarías al ver esta tabla?

 

La gran mayoría de esta muestra tiene grupo sanguíneo O ó A con un 46% y 42% respectivamente y que los grupos B y AB son minoritarios, siendo el AB la modalidad minoritaria.

1.4.2 Ejemplo 2

Otro ejemplo: las edades en un grupo de \(n = 25\) estudiantes universitarios

Valores de la variable Frecuecias Absolutas Frecuencias relativas Frecuencias Absolutas acumuladas Frecuencias Relativas acumuladas
\(x_i\) \(f_i\) \(p_i\) \(F_i\) \(P_i\)
18 6 0.24 6 0.24
19 5 0.20 11 0.44
20 3 0.12 14 0.56
21 3 0.12 17 0.68
22 3 0.12 20 0.80
23 3 0.12 23 0.92
24 2 0.08 25 1
Total 25 1 25 1

Contesta a las siguientes preguntas sobre la tabla anterior:

  • ¿Cuántos individuos tienen 21 años?

  • ¿Qué porcentaje de individuos tiene más de 19 años?

1.4.3 Ejemplo 3

¿Qué pasa cuando tenemos una variable cuantitativa continua?

Imagina que anotamos las puntuaciones obtenidas por 100 pacientes en un test psicológico en una escala continua del 0 al 100.

\(x_i\): 11,42,58,25,48,18,45,35,59,29,35,2,37,68,70,31,44,84,64,82,26,42,51,29, 59,92,56,5,52,8,1,12,21,6,32,15,67,47,61,47,43,33,48,47,43,69,49,21,9,15,11,22, 29,14,31,46,19,49,51,71,52,32,51,44,58,60,43,65,73,62,3,17,39,22,40,65,30,31,16, 80,41,59,60,41,51,10,63,41,74,81,20,36,59,38,40,43,18,60,71,44.

¿Tiene sentido hacer una tabla de frecuencias? ¿Nos resume la información? ¿Qué podemos hacer?

\(x_i\) \(f_i\) \(p_i\) \(F_i\) \(P_i\)
[0,10] 8 0.08 8 0.08
(10,20] 12 0.12 20 0.20
(20,30] 10 0.1 30 0.30
(30,40] 14 0.14 44 0.44
(40,50] 21 0.21 65 0.65
(50,60] 16 0.16 81 0.81
(60,70] 10 0.10 91 0.91
(70,80] 5 0.05 96 0.96
(80,90] 3 0.03 99 0.99
(90,100] 1 0.01 100 1
Total 100 1

1.4.4 Tablas de frecuencia en R

Los resúmenes numéricos deberíamos saber hacerlos en R con datos |> summarise() pero… ¿y las tablas de frecuencia o contigencia (unidimensionales de momento)?. Por ejemplo, vamos a realizar un conteo de frecuencias de la variable hair_color de starwars. Para ello en tidyverse basta usar count()

tabla_freq <- 
  starwars |>
  drop_na(hair_color) |> 
  count(hair_color)
tabla_freq
# A tibble: 11 × 2
   hair_color        n
   <chr>         <int>
 1 auburn            1
 2 auburn, grey      1
 3 auburn, white     1
 4 black            13
 5 blond             3
 6 blonde            1
 7 brown            18
 8 brown, grey       1
 9 grey              1
10 none             38
11 white             4

Si te fijas la frecuencia absoluta viene siempre como \(n\) pero podemos renombrarla

tabla_freq <-
  tabla_freq |> 
  rename(frec_abs = n)
tabla_freq
# A tibble: 11 × 2
   hair_color    frec_abs
   <chr>            <int>
 1 auburn               1
 2 auburn, grey         1
 3 auburn, white        1
 4 black               13
 5 blond                3
 6 blonde               1
 7 brown               18
 8 brown, grey          1
 9 grey                 1
10 none                38
11 white                4

A esa tabla de frecuencias podemos añadirle la frecuencia relativa calculada como cada frecuencia absoluta dividida por el total (la suma de todos)

tabla_freq <-
  tabla_freq |> 
  mutate("frec_rel" = frec_abs / sum(frec_abs))
tabla_freq
# A tibble: 11 × 3
   hair_color    frec_abs frec_rel
   <chr>            <int>    <dbl>
 1 auburn               1   0.0122
 2 auburn, grey         1   0.0122
 3 auburn, white        1   0.0122
 4 black               13   0.159 
 5 blond                3   0.0366
 6 blonde               1   0.0122
 7 brown               18   0.220 
 8 brown, grey          1   0.0122
 9 grey                 1   0.0122
10 none                38   0.463 
11 white                4   0.0488

Este proceso podemos obtenerlo de forma más sencilla con R base (recuerda: funciones aplican a vectores aislados, que debes sacar de la tabla con $ y sin tuberías) con la función table()

tabla_freq <-
 table(starwars$hair_color)
tabla_freq

       auburn  auburn, grey auburn, white         black         blond 
            1             1             1            13             3 
       blonde         brown   brown, grey          grey          none 
            1            18             1             1            38 
        white 
            4 

También podemos obtener en R base las frecuencias realtivas aplicando prop.table() a la tabla de frecuencias anterior.

prop.table(tabla_freq)

       auburn  auburn, grey auburn, white         black         blond 
   0.01219512    0.01219512    0.01219512    0.15853659    0.03658537 
       blonde         brown   brown, grey          grey          none 
   0.01219512    0.21951220    0.01219512    0.01219512    0.46341463 
        white 
   0.04878049 

Moraleja: no te cases de manera acérrima con una forma de hacer las cosas, ambos mundos van a ser necesarios.

1.4.5 Paréntesis: sample

Imagina que queremos añadir una columna nueva llamada rol tal que a cada persona le asignamos de manera aleatoria "bueno" (con probabilidad 0.45), "malo" (con probabilidad 0.35), "villano" (con probabilidad 0.2)

Para generar experimentos aleatorios de una variable cualitativa contamos con sample(x = ..., size = ..., replace = ..., probs = ...):

  • x = c("cruz", "cara"): las opciones que permitimos que salgan.
  • size = 20: las veces que «tiramos la moneda».
  • replace = TRUE: si permitimos reemplazamiento (pueden salir elementos repetidos) o no (en este caso solo podríamos tirar 2 veces).
  • prob = c(0.3, 0.7): las probabilidades de los posibles eventos

En nuestro caso de ejemplo estamos tirando una moneda trucada (más caras que cruces) 20 veces.

sample(x = c("cruz", "cara"), size = 20, replace = TRUE, prob = c(0.3, 0.7))
 [1] "cruz" "cruz" "cruz" "cara" "cara" "cruz" "cara" "cruz" "cara" "cruz"
[11] "cara" "cara" "cara" "cara" "cruz" "cara" "cara" "cruz" "cruz" "cruz"

1.4.6 Frecuencias acumuladas

Imagina que queremos añadir una columna nueva llamada rol tal que a cada persona le asignamos de manera aleatoria "bueno" (con probabilidad 0.45), "malo" (con probabilidad 0.35), "villano" (con probabilidad 0.2)

Tendremos que hacer un sample() con las 3 opciones (y sus probabilidades) de tamaño 87 (tenemos 87 personajes).

starwars <- 
  starwars |> 
  mutate("rol" = sample(x = c("bueno", "malo", "villano"), size = 87,
                        replace = TRUE, prob = c(0.45, 0.35, 0.2)),
         .after = name)
starwars
# A tibble: 87 × 15
   name      rol   height  mass hair_color skin_color eye_color birth_year sex  
   <chr>     <chr>  <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr>
 1 Luke Sky… vill…    172    77 blond      fair       blue            19   male 
 2 C-3PO     vill…    167    75 <NA>       gold       yellow         112   none 
 3 R2-D2     vill…     96    32 <NA>       white, bl… red             33   none 
 4 Darth Va… bueno    202   136 none       white      yellow          41.9 male 
 5 Leia Org… malo     150    49 brown      light      brown           19   fema…
 6 Owen Lars bueno    178   120 brown, gr… light      blue            52   male 
 7 Beru Whi… bueno    165    75 brown      light      blue            47   fema…
 8 R5-D4     bueno     97    32 <NA>       white, red red             NA   none 
 9 Biggs Da… malo     183    84 black      light      brown           24   male 
10 Obi-Wan … bueno    182    77 auburn, w… fair       blue-gray       57   male 
# ℹ 77 more rows
# ℹ 6 more variables: gender <chr>, homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>

Si te fijas esa variable no solo es cualitativa sino ordinal. Entre las variables cualitativas tenemos nominales (género, sexo, estado civil, etc) y ordinales (estado de salud, rol, etc). ¿Cómo distinguirlas? La forma que tenemos en R de indicarle que una variable de tipo texto (universo informático) es una cualitativa y de qué tipo (universo estadística) es haciendo uso de lo que se conoce como factores

1.4.7 Paréntesis: factores

En R las variables cualitativas pueden ser tratadas como tales convirtiendo una cadena de texto a lo que se conoce como factor. Por ejemplo, supongamos que tenemos un vector de notas

notas <- c("suspenso", "notable", "suspenso", "aprobado", "notable", "suspenso")
notas
[1] "suspenso" "notable"  "suspenso" "aprobado" "notable"  "suspenso"

Para convertir a factor nos basta con factor(). ¿Qué notas diferente?

notas_fct <- factor(notas)
notas_fct
[1] suspenso notable  suspenso aprobado notable  suspenso
Levels: aprobado notable suspenso

Si te fijas ahora tenemos disponibles unos niveles (levels): son las posibles modalidades de nuestra variable cualitativa, el soporte, de manera que aunque borremos uno de ellos (vamos a borrar todos los aprobados), la opción sigue disponible si entrase un dato nuevo (algo así como un menú de opciones permitidas)

notas_fct[notas_fct != "aprobado"]
[1] suspenso notable  suspenso notable  suspenso
Levels: aprobado notable suspenso

En el caso de las cualitativas ordinales podemos incluso establecer una jerarquía, indicando explícitamente los niveles y ordered = TRUE

notas_fct_ord <- factor(notas, levels = c("aprobado", "notable", "suspenso"),
                        ordered = TRUE)
notas_fct_ord
[1] suspenso notable  suspenso aprobado notable  suspenso
Levels: aprobado < notable < suspenso

Fíjate que ahora tenemos una jerarquía y aunque sea cualitativa podemos buscar elementos <= o >= que otros

notas_fct_ord[notas_fct_ord <= "notable"]
[1] notable  aprobado notable 
Levels: aprobado < notable < suspenso

1.4.8 Frecuencias acumuladas

Volvamos a nuestro ejemplo: ¿cómo convertir nuestra nueva variable rol en una variable cualitativa ordinal (en orden de maldad)? Debemos usar el concepto de factor pero para no aislar la variable de su tabla, lo introduciremos en un mutate()

starwars <-
  starwars |> 
  mutate("rol" = factor(rol, levels = c("bueno", "malo", "villano"),
                        ordered = TRUE))

Cuando tenemos una variable ordinal no solo vamos a poder calcular la tabla de frecuencias absoluta y relativa…

tabla_freq <-
  starwars |> 
  count(rol) |> 
  mutate("frec_rel" = n/sum(n))
tabla_freq
# A tibble: 3 × 3
  rol         n frec_rel
  <ord>   <int>    <dbl>
1 bueno      40    0.460
2 malo       27    0.310
3 villano    20    0.230
# o bien
table(starwars$rol)

  bueno    malo villano 
     40      27      20 

…sino que al tener una jerarquía de orden (fíjate que salen automáticamente ordenados) vamos a poder calcular las frecuencias acumuladas con cumsum()

tabla_freq <-
  tabla_freq |>
  mutate("frec_abs_acum" = cumsum(n),
         "frec_rel_acum" = cumsum(frec_rel))
tabla_freq
# A tibble: 3 × 5
  rol         n frec_rel frec_abs_acum frec_rel_acum
  <ord>   <int>    <dbl>         <int>         <dbl>
1 bueno      40    0.460            40         0.460
2 malo       27    0.310            67         0.770
3 villano    20    0.230            87         1    
# o bien
cumsum(table(starwars$rol))
  bueno    malo villano 
     40      67      87 
cumsum(prop.table(table(starwars$rol)))
    bueno      malo   villano 
0.4597701 0.7701149 1.0000000 

1.5 💻 Tu turno

Intenta realizar los siguientes ejercicios sin mirar las soluciones

📝 Para repasar lo aprendido vamos a poner todo en práctica con el dataset SatisfaccionPacientes.csv que tenéis subido al campus. ¿Cómo importarlo?.

Code
library(readr) # dentro de tidyverse
# en mi caso tengo el .csv en una carpeta datos dentro del proyecto
datos <-
  read_csv(file = "./datos/SatisfaccionPacientes.csv") |> 
  # la función clean_names del paquete janitor 
  # nos normaliza nombres de variables
  janitor::clean_names()
Rows: 100 Columns: 8
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Genero, EstadoCivil, EstadoSalud
dbl (5): ID, Edad, TiempoEspera, GradoSatisfaccion, NumeroVisitas

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

📝 Aplica el código que sea necesario para responder a estas preguntas. ¿Cuál es el tamaño muestral? ¿Cuántas variables tenemos? ¿Cuántas modalidades tenemos en la variable estado_civil (y cuantas observaciones en cada una)?

Code
# Tamaño muestral / número de observaciones
n <- nrow(datos)

# Número de variables
p <- ncol(datos)

# ¿Qué modalidades tenemos?
datos |> 
  count(estado_civil)

📝 Determina el tipo de variable (cuantitativa vs. cualitativa).

Code
# Variables cuantitativas: tiempo, grado satisfacción, número de visitas
# Variables cualitativas: género, estado civil, estado salud
glimpse(datos)

📝 Obten tablas de frecuencias (absoluta y relativa) en el caso de las cualitativas NOMINALES. Con ella intenta responder a las preguntas: a) ¿cuántas mujeres hay? b) ¿qué % de individuos están casados?

Code
# no podemos calcular acumulados ya que  genero es nominal
freq_genero <-
  datos |> 
  count(genero) |> 
  rename(frecuencia_abs = n) |> 
  mutate(frecuencia_rel = frecuencia_abs/sum(frecuencia_abs))
# Hay 53 mujeres

freq_estado_civil <-
  datos |> 
  count(estado_civil) |> 
  rename(frecuencia_abs = n) |> 
  mutate(frecuencia_rel = frecuencia_abs/sum(frecuencia_abs))
# Hay 26% personas casadas

📝 Convierte de manera adecuada la variable genero y estado_civil a cualitativa nominal

Code
datos <-
  datos |>
  mutate(estado_civil = factor(estado_civil),
         genero = factor(genero))

📝 Calcula la media, mediana, rango intercuartílico y desviación típica de edad y tiempo de espera.

Code
resumen <-
  datos |>
  summarise(media_edad = mean(edad), sd_edad = sd(edad), mediana_edad = median(edad),
           IQR_edad = quantile(edad, probs = 0.75) - quantile(edad, probs = 0.25),
           # tiempo espera
           media_tiempo_espera = mean(tiempo_espera), sd_tiempo_espera = sd(tiempo_espera),
           mediana_tiempo_espera = median(tiempo_espera),
           IQR_tiempo_espera = quantile(tiempo_espera, probs = 0.75) - quantile(tiempo_espera, probs = 0.25))

📝 Repite el anterior ejercicio pero obteniendo las métricas desagregadas por sexo.

Code
resumen <-
  datos |>
  summarise(media_edad = mean(edad), sd_edad = sd(edad), mediana_edad = median(edad),
           IQR_edad = quantile(edad, probs = 0.75) - quantile(edad, probs = 0.25),
           # tiempo espera
           media_tiempo_espera = mean(tiempo_espera), sd_tiempo_espera = sd(tiempo_espera),
           mediana_tiempo_espera = median(tiempo_espera),
           IQR_tiempo_espera = quantile(tiempo_espera, probs = 0.75) - quantile(tiempo_espera, probs = 0.25),
          .by = genero)

📝 Realiza un gráfico de violín para la variable tiempo_espera para cada género

Code
ggplot(datos) +
  geom_violin(aes(x = genero, y = tiempo_espera, fill = genero, color = genero),
              alpha = 0.7) +
  ggthemes::scale_color_colorblind() +
  ggthemes::scale_fill_colorblind() +
  theme_minimal()

2 🐣 Caso práctico: encuesta de satisfacción

Vamos a seguir poniendo en práctica lo aprendido el dataset SatisfaccionPacientes.csv que tenéis subido al campus, tras haberle normalizado nombres y convertido las variables que tocaban a cualitativas nominales.

library(readr) # dentro de tidyverse
# en mi caso tengo el .csv en una carpeta datos dentro del proyecto
datos <-
  read_csv(file = "./datos/SatisfaccionPacientes.csv") |> 
  # la función clean_names del paquete janitor 
  # nos normaliza nombres de variables
  janitor::clean_names() |>
  mutate(estado_civil = factor(estado_civil),
         genero = factor(genero))
Rows: 100 Columns: 8
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Genero, EstadoCivil, EstadoSalud
dbl (5): ID, Edad, TiempoEspera, GradoSatisfaccion, NumeroVisitas

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
datos
# A tibble: 100 × 8
      id  edad genero    estado_civil tiempo_espera grado_satisfaccion
   <dbl> <dbl> <fct>     <fct>                <dbl>              <dbl>
 1     1    60 Masculino Casado                  28                  8
 2     2    44 Femenino  Soltero                 22                  8
 3     3    43 Masculino Soltero                  8                  9
 4     4    32 Masculino Soltero                 21                  8
 5     5    66 Masculino Divorciado               7                 10
 6     6    43 Masculino Divorciado              20                  8
 7     7    54 Masculino Casado                  18                  6
 8     8    55 Masculino Soltero                 29                  6
 9     9    56 Masculino Viudo                   17                  9
10    10    34 Femenino  Casado                  34                  8
# ℹ 90 more rows
# ℹ 2 more variables: numero_visitas <dbl>, estado_salud <chr>

2.1 Pregunta 1

Convierte de manera adecuada la variable estado_salud a cualitativa ORDINAL

Code
datos <-
  datos |>
  mutate(estado_salud =
           factor(estado_salud, levels = c("Malo", "Regular", "Bueno", "Excelente"),
                  ordered = TRUE))

2.2 Pregunta 2

Haz uso de table() para calcular la tabla de frecuencias de genero y estado_civil

Code
table(datos$genero)
table(datos$estado_civil)

2.3 Pregunta 3

Calcula la tabla de frecuencias de las ORDINALES y piensa si ahora puedes añadir algo más a la tabla de frecuencias). Tras ello usa el código más sencillo para responder a: ¿cuántas personas tienen un estado de salud regular (o peor)?

Code
freq_estado_salud <-
  datos |> 
  count(estado_salud) |> 
  rename(frecuencia_abs = n) |> 
  mutate(frecuencia_rel = frecuencia_abs/sum(frecuencia_abs),
         frecuencia_acum_abs = cumsum(frecuencia_abs),
         frecuencia_acum_rel = cumsum(frecuencia_rel))
# Se ve dentro de la tabla. Hay 44+15 = 59 personas con un estado de salud malo o regular. 
# Con código
datos |>
  count(estado_salud <= "Regular")

2.4 Pregunta 4

Si te fijas una de las modalidades es totalmente anecdótica (solo 1 Excelente). Sería conveniente recategorizar la categoría Excelente: siempre que detecte Excelente, lo debe recategorizar a Bueno (criterio general: las categorías deben contener al menos un 5% de los individuos de toda la muestra). Pista: mutate e if_else

Code
datos <- 
  datos |> 
  mutate(estado_salud  = if_else(estado_salud  == "Excelente", "Bueno", estado_salud),
         # ojo: hay que redefinir los niveles de la cualitativa
         # ya que ha dejado de ser factor (veremos un día el paquete forcats para esto)
         estado_salud =
           factor(estado_salud, levels = c("Malo", "Regular", "Bueno"),
                  ordered = TRUE))

2.5 Pregunta 5

Calcula la media, mediana, rango intercuartílico y desviación típica de grado de satisfacción desagregado por sexo.

Code
resumen <-
  datos |>
  summarise(media_grado_satisfaccion = mean(grado_satisfaccion),
           sd_grado_satisfaccion = sd(grado_satisfaccion),
           mediana_grado_satisfaccion = median(grado_satisfaccion),
           IQR_grado_satisfaccion =
             quantile(grado_satisfaccion, probs = 0.75) -
             quantile(grado_satisfaccion, probs = 0.25),
           .by = genero)

2.6 Pregunta 6

Exporta los resultados anteriores (resumen) en un archivo resumen.csv. En lugar de un read_csv() vamos a usar write_csv(tabla, file = "ruta")

Code
# importado como csv
write_csv(resumen, file = "./resumen.csv")

2.7 Pregunta 7

Crear un diagrama de barras para la variable género.

Code
# Género: fíjate que por defecto `geom_bar()` cuenta y visualiza ese conteo `n`.
ggplot(datos) +
  geom_bar(aes(x = genero)) 

2.8 Pregunta 8

¿Cómo podríamos decirle que cada barra (es decir, para cada modalidad de género) sea de un color (de relleno)?

Code
ggplot(datos) +
  # dentro de aes() para que dependa de la tabla
  geom_bar(aes(x = genero, fill = genero))

2.9 Pregunta 9

En un gráfico no solo podemos usar color como parámetro estético el color sino jugar por ejemplo con la transparencia (parámetro alpha). Modifica el gráfico anterior para hacer los colores un poco más transparentes.

Code
ggplot(datos) +
  geom_bar(aes(x = genero, fill = genero), alpha = 0.75) 

2.10 Pregunta 10

Una capa muy importante en ggplot es labs(). Añade títulos a los ejes, leyendas, título de gráfica, subtítulo y pie de figura.

Code
ggplot(datos) +
  geom_bar(aes(x = genero, fill = genero), alpha = 0.75) +
  labs(title = "Diagrama de barras de la variable género", 
       subtitle = "Encuesta satisfacción",
       caption = "Autor: J. Álvarez y A. Moreno",
       x = "Categoría", y = "Frecuencia absoluta", fill = "Categoría")

2.11 Pregunta 11

También podemos añadir una capa de tema: unos ajustes (fuente de letra, tamaño, colores de fondo, etc) ya predefinidos. El más “austero” pero cuco es theme_minimal()

ggplot(datos) +
  geom_bar(aes(x = genero, fill = genero), alpha = 0.75) +
  labs(title = "Diagrama de barras de la variable género", 
       x = "Categoría", y = "Frecuencia absoluta",
       fill = "Categoría") +
  theme_minimal() 

Tienes más temas en el paquete {ggthemes}

ggplot(datos) +
  geom_bar(aes(x = genero, fill = genero), alpha = 0.75) +
  labs(title = "Diagrama de barras de la variable género", 
       x = "Categoría", y = "Frecuencia absoluta",
       fill = "Categoría") +
  ggthemes::theme_economist()

Haz el gráfico anterior pero decidiendo tú qué colores asignas a cada género y con un tema

Code
ggplot(datos) +
  geom_bar(aes(x = genero, fill = genero), alpha = 0.75) +
  # reminder: el relleno es fill, color para el reborde si quieres
  scale_fill_manual(values = c("#379e98", "#eaea3e")) +
  labs(title = "Diagrama de barras de la variable género", 
       x = "Categoría", y = "Frecuencia absoluta",
       fill = "Categoría") +
 theme_minimal()

En el paquete {ggthemes} tienes ya algunas paletas a usar si quieres, por ejemplo para personas daltónicas scale_fill_colorblind()

ggplot(datos) +
  geom_bar(aes(x = genero, fill = genero), alpha = 0.75) +
  ggthemes::scale_fill_colorblind() +
  labs(title = "Diagrama de barras de la variable género", 
       x = "Categoría", y = "Frecuencia absoluta",
       fill = "Categoría") +
 theme_minimal()

2.12 Pregunta 12

Crear desde cero un diagrama de barras, con ajustes personalizados vistos en los ejercicios anterioes, para la variable estado de salud

Code
# Estado de salud (ahora el orden importa)
ggplot(datos) +
  geom_bar(aes(x = estado_salud, fill = estado_salud), alpha = 0.75) +
  ggthemes::scale_fill_colorblind() +
  labs(title = "Diagrama de barras de la variable estado salud", 
       x = "Categoría",  y = "Frecuencia absoluta",
       fill = "Categoría") +
  theme_minimal() 

Fíjate que si no tuviésemos la variable como cuali ordinal, las barras van por orden alfabético, no por jerarquía real

ggplot(datos) +
  geom_bar(aes(x = as.character(estado_salud), fill = as.character(estado_salud)),
           alpha = 0.75) +
  ggthemes::scale_fill_colorblind() +
  labs(title = "Diagrama de barras de la variable estado salud", 
       x = "Categoría",  y = "Frecuencia absoluta",
       fill = "Categoría") +
  theme_minimal() 

2.13 Pregunta 13

Crea el histograma inferior para las variable edad y tiempo de espera.

Code
ggplot(datos) +
  geom_histogram(aes(x = edad), bins = 30, fill = "darkorange", alpha = 0.75) + 
  labs(title = "Histograma de edad", subtitle = "Bins = 30",
       x = "Valores", y = "Frecuencia absoluta") +
  theme_minimal()

Code
ggplot(datos) +
  # Define el ancho de las barras y colores
  geom_histogram(aes(x = tiempo_espera), bins = 30, fill = "orchid", alpha = 0.75) + 
  labs(title = "Histograma de tiempo de espera", subtitle = "Bins = 30",
       x = "Valores", y = "Frecuencia absoluta") +
  theme_minimal()

2.14 Pregunta 14

Crea el gráfico de densidad inferior para las variable edad y tiempo de espera.

Code
ggplot(datos) +
  geom_density(aes(x = edad), color = "darkorange", 
               fill = "darkorange", alpha = 0.75) + 
  labs(title = "Gráfico de densidad de edad",
       x = "Valores", y = "Frecuencia relativa") +
  theme_minimal()

Code
ggplot(datos) +
  geom_density(aes(x = tiempo_espera), color = "orchid", 
               fill = "orchid", alpha = 0.75) + 
  labs(title = "Gráfico de densidad de tiempo de espera",
       x = "Valores", y = "Frecuencia relativa") +
  theme_minimal()

2.15 Pregunta 15

Crea el histograma inferior para la variable grado_satisfaccion. ¿Qué opinas?

Code
# Representación regular, no aporta ni resume
ggplot(datos) +
  # Define el ancho de las barras y colores
  geom_histogram(aes(x = grado_satisfaccion), bins = 30, fill = "#308b8e", alpha = 0.75) + 
  labs(title = "Histograma de grado de satisfacción", subtitle = "Bins = 30",
       x = "Valores", y = "Frecuencia absoluta") +
  theme_minimal()

Code
# Las **variables discretas muchas veces son mejor representadas** con una diagrama de barras

2.16 Pregunta 16

Realiza un boxplot para edad y un boxplot para numero de visitas PERO por género (dos variables, piensa cómo)

Code
ggplot(datos) +
  geom_boxplot(aes(y = edad), fill = "lightblue", alpha = 0.75) +  
  labs(title = "Boxplot de edad",  y = "Edad") +
  theme_minimal()

Code
ggplot(datos) +
  geom_boxplot(aes(x = genero, y = tiempo_espera, fill = genero),
               alpha = 0.75) +
  labs(title = "Boxplot de tiempo de espera por género", 
       x = "Género", y = "Tiempo de Espera") +
  theme_minimal()

Haciendo uso del gráfico anterior:

  1. ¿La variable edad tiene outliers? ¿Qué edad tienen esos pacientes?

  2. ¿Quién ha esperado más los hombres o las mujeres?

En los boxplots podemos también indicar parámetros concretos para los outliers.

ggplot(datos) +
  geom_boxplot(aes(y = edad), fill = "lightblue", alpha = 0.75,
               outlier.colour = "red", outlier.shape = 18, outlier.size = 3) +  
  labs(title = "Boxplot de edad",  y = "Edad") +
  theme_minimal()

3 Estadística descriptiva bivariante

Todo lo que hemos hecho con una variable podemos hacerlo también de manera bivariante considerando dos variables. Uno de los principales objetivos de la estadística bivariante es determinar si existe relación o dependencia entre dos variables, es decir, cuando un cambio en el valor de una de ellas se asocia a un cambio en el de la otra (una dependencia estadística no implica un efecto causal). La situación contraria, es decir, la ausencia de relación, se denomina independencia.

Una primera aproximación al estudio de dos variables será clasificar el tipo de análisis

  • Cuali vs cuali:
    • Resumen: tablas de contigencia (frecuencia cruzada).
    • Inferencia: prueba \(\chi^2\) de independencia o test de Fisher.
    • Gráficos: barras apiladas, gofres, gráficos de «flujo».
  • Cuanti vs cuanti:
    • Resumen: covarianza y correlación.
    • Inferencia: test de correlación (relación lineal) y test de Kolmogorov-Smirnov (¿ambas distribuciones son iguales?). Test de igualdad de medias o igualdad de varianzas
    • Gráficos: diagrama de dispersión, correlogramas, heatmaps.
  • Cuanti vs cuali:
    • Resumen: medidas de centralización/dispersión/posición de la cuanti desagregado por los grupos de la cuali.
    • Inferencia: ANOVA (una vía, dos vías, …). Test de igualdad de medias o igualdad de varianzas (desagregada por grupos)
    • Gráficos: boxplots, gráficos de violín (desagregados por grupos)

3.1 Introducción a inferencia

¿Pero que es eso de la inferencia estadística? Es un conjunto de métodos y técnicas que permite inferir conclusiones sobre una población a partir de una muestra de datos.

Su propósito es utilizar la información muestral para estimar características de la población, probar hipótesis y realizar predicciones, basado en el cálculo de estadísticos

  • Parámetro: medida que describe una característica de la población (ejemplo: la media poblacional \(\mu\) de la estatura de las mujeres en España).

  • Estadístico: medida que describe una característica de la muestra (ejemplo: la media muestral \(\overline{x}\) de un conjunto de 100 mujeres).

Haciendo uso de estadísticos que aproximen una correcta estimación de los parámetros, los contraste de hipótesis son procedimientos estadísticos para tomar decisiones sobre la validez de una afirmación acerca de una población en función de los datos muestrales.

La idea es muy parecido a un juicio: con las pruebas (muestra) el jurado (estadístico) deben decidir sobre tu culpabilidad real (población), pudiendo ser declarado culpable o no culpable. Este proceso implica formular

  • Hipótesis nula \(H_0\): es una afirmación generalmente representa una posición de no efecto o no diferencia (ejemplo: entras siendo no culpable a un juicio)

  • Hipótesis alternativa \(H_0\): es una afirmación que se acepta si se rechaza la hipótesis nula. Representa un efecto o diferencia (ejemplo: culpable)

La idea es similar a la del juicio: solo vamos a rechazar \(H_0\) (es decir, aceptar \(H_1\)) si hay MUCHAS EVIDENCIAS en la muestra (solo se condena culpable a una persona si hay muchas evidencias que demuestran su culpabilidad, pero el acusado no tiene que demostrar su inocencia).

 

Llamaremos nivel de significancia \(\alpha\) a la probabilidad de rechazar la hipótesis nula cuando es verdadera (condenar a un inocente, conocido como error tipo I. Normalmente \(\alpha = 0.05\) aunque se pueden usar otros valores como 0.01 o 0.10 (a decidir ANTES de realizar el contraste.)

3.1.1 Ejemplo

Supongamos que estamos probando si un nuevo medicamento tiene un efecto en la presión arterial \(\mu\)

\[H_0:~\mu = \mu_0~\text{(medicamento no tiene efecto sobre la presión arterial)}\] \[H_1:~\mu \neq \mu_0~\text{(medicamento SI tiene efecto sobre la presión arterial)}\]

donde \(\mu_0\) es la media de la presión arterial antes del tratamiento.

Decisión \(H_0\) es cierta \(H_1\) es cierta
Se decide rechazar \(H_0\) Error de tipo I Acierto
Se decide no rechazar \(H_0\) Acierto Error de tipo II

3.1.2 p-valor

El conocido como p-valor es uno de los conceptos más importantes en estadística pero también peor usados. Puedes ver toda una revisión de qué significa y qué no en https://pmc.ncbi.nlm.nih.gov/articles/PMC4877414/

Podemos definir el p-valor como un valor continuo que nos mide la compatibilidad de los datos observados con el modelo e hipótesis asumidas: 1 indica compatibilidad perfecta y 0 incompatibilidad completa.

  • No repesenta la probabilidad de que la hipótesis nula sea cierta: el propio p-valor se calcula ASUMIENDO que lo es.

  • No repesenta la probabilidad de que, por azar, se produzca nada

3.2 Análisis de variables cuali vs cuali

Una vez visto conceptos básicos de inferencia vamos a empezar por un análisis bivariante de dos variables cualitativas.

3.2.1 Tablas de contigencia

El primer paso siempre será intentar resumir la información mediante el uso de tablas de contigencia, en este caso bidimensionales.

 

¿Cómo lo harías con tidyverse? ¿Y con R base?

Vamos a tomar de nuevo nuestros datos de satisfacción de pacientes

library(readr)
datos <-
  read_csv(file = "./datos/SatisfaccionPacientes.csv") |> 
  janitor::clean_names()
Rows: 100 Columns: 8
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Genero, EstadoCivil, EstadoSalud
dbl (5): ID, Edad, TiempoEspera, GradoSatisfaccion, NumeroVisitas

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Para calcular una tabla bidimensional de frecuencias en tidyverse basta con indicar dos variables en count()

datos |>
  count(genero, estado_civil)
# A tibble: 8 × 3
  genero    estado_civil     n
  <chr>     <chr>        <int>
1 Femenino  Casado          11
2 Femenino  Divorciado      11
3 Femenino  Soltero         22
4 Femenino  Viudo            9
5 Masculino Casado          15
6 Masculino Divorciado       8
7 Masculino Soltero         20
8 Masculino Viudo            4

Lo habitual es mostrar esta tabla como una tabla con m filas y n columnas, siendo \(m\) el número de modalidades distintas de la primera variable (en este caso \(m=2\), femenino y masculino) y \(n\) el número de modalidades distintas de la segunda variable (en este caso \(n = 4\)).

¿Cómo hacer que la variable estado_civil pivote para pasar de estar en vertical a estar «en horizontal»? (echa un repaso a la parte de tidy data)

datos |>
  count(genero, estado_civil) |> 
  pivot_wider(names_from = estado_civil, values_from = n)
# A tibble: 2 × 5
  genero    Casado Divorciado Soltero Viudo
  <chr>      <int>      <int>   <int> <int>
1 Femenino      11         11      22     9
2 Masculino     15          8      20     4

Esto se puede hacer mucho más sencillo de nuevo en R base con table()

table(datos$genero, datos$estado_civil)
           
            Casado Divorciado Soltero Viudo
  Femenino      11         11      22     9
  Masculino     15          8      20     4

Fíjate que ahora podemos normalizar las frecuencias de 3 formas: respecto al total de los datos, por filas (margin = 1) o por columnas (margin = 2).

prop.table(table(datos$genero, datos$estado_civil))
           
            Casado Divorciado Soltero Viudo
  Femenino    0.11       0.11    0.22  0.09
  Masculino   0.15       0.08    0.20  0.04
prop.table(table(datos$genero, datos$estado_civil), margin = 1)
           
                Casado Divorciado    Soltero      Viudo
  Femenino  0.20754717 0.20754717 0.41509434 0.16981132
  Masculino 0.31914894 0.17021277 0.42553191 0.08510638
prop.table(table(datos$genero, datos$estado_civil), margin = 2)
           
               Casado Divorciado   Soltero     Viudo
  Femenino  0.4230769  0.5789474 0.5238095 0.6923077
  Masculino 0.5769231  0.4210526 0.4761905 0.3076923

Haciendo uso de las tablas anteriores intenta responder a las siguientes preguntas:

  1. ¿Qué cantidad de pacientes mujeres están solteras?

  2. ¿Qué porcentaje, de entre los pacientes hombres, están viudos?

  3. ¿Qué porcentaje, de entre los que están divorciados, son mujeres?

  4. ¿Qué porcentaje (del total de pacientes) son hombres solteros?

Code
# a) 22 mujeres
# b) 8.51%
# c) 57.89%
# d) 20%
3.2.1.1 Visualización de tablas: geom_tile()

Puedes incluso visualizar dichas cantidades con geom_tile() indicándole que el relleno dependa del conteo n

datos |>
  count(genero, estado_civil) |>
  ggplot() +
  geom_tile(aes(x = genero, y = estado_civil, fill = n)) +
  theme_minimal()

3.2.2 Inferencia cuali vs cuali: prueba chi-cuadrado

Esas tablas de frecuencia serán las que usen los diferentes contrastes para decidir si hay o no dependencia entre ellas.

 

El contraste más conocido es la conocida como prueba de \(\chi^2\) (chi-cuadrado): dada una tabla de contigencia entre dos cualitativas, el contraste compara dicha tabla con la que deberíamos obtener bajo la hipótesis nula de independencia

Vamos a hacerlo con nuestras variables genero y estado_civil

\[H_0:~\text{genero y estado civil son independientes}\]

\[H_1:~\text{genero y estado civil son dependientes}\]

table(datos$genero, datos$estado_civil)
           
            Casado Divorciado Soltero Viudo
  Femenino      11         11      22     9
  Masculino     15          8      20     4

Si la hipótesis nula fuese cierta, ¿qué esperaríamos?

  1. Elegimos uno de los factores y calculamos su proporción en la tabla general (53% vs 47% en este caso)
prop.table(table(datos$genero))

 Femenino Masculino 
     0.53      0.47 
  1. Calculamos la tabla de contigencia de ambas variables obteniendo lo que denotaremos como frecuencias observadas \(O_{ij}\)
table(datos$genero, datos$estado_civil)
           
            Casado Divorciado Soltero Viudo
  Femenino      11         11      22     9
  Masculino     15          8      20     4
  1. Si ambas variables fuesen independientes, en cada columna tendríamos que tener porcentajes parecidos a cuando lo hacemos sin desagregar (53% mujeres y 47% hombres). Es decir, del total de casados (26) deberíamos tener \(8.48\) mujeres y \(7.52\) hombres; del total de divorciados (19) deberíamos tener \(10.07\) mujeres y \(8.93\) hombres; y así sucesivamente. Estas frecuencias las denotaremos como frecuencias esperadas \(E_{ij}\)

\[E_{ij} = \frac{\text{suma fila i * suma fila j}}{\text{total}}\]

  1. Resumimos lo que se desvía una de otra mediante el estadístico chi-cuadrado:

\[\begin{eqnarray}\chi^2 &=& \sum_{i,j} \frac{\left(O_{ij} - E_{ij} \right)^2}{E_{ij}} = \frac{(13.78 - 11)^2}{13.78} + \frac{(12.22 - 15)^2}{12.22} \nonumber \\ &+& \frac{(10.07 - 11)^2}{10.07} + \ldots + \frac{(6.11 - 4)^2}{6.11} = 2.75731\end{eqnarray}\]

  1. Calculamos cómo de extremo es el valor del estadístico si la hipótesis nula fuese cierta, proporcionándonos un p-valor.

Este proceso podemos hacerlo directamente aplicando chisq.test(), indicándole las variables (o su tabla de frecuencias)

contraste <- chisq.test(datos$genero, datos$estado_civil)
  • ...$statistic: tenemos guardado el valor del estadístico
contraste$statistic
X-squared 
  2.75731 
  • ...$observed: tenemos guardada la tabla de frecuencias observada
contraste$observed
            datos$estado_civil
datos$genero Casado Divorciado Soltero Viudo
   Femenino      11         11      22     9
   Masculino     15          8      20     4
  • ...$expected: tenemos guardada la tabla de frecuencias esperada
contraste$expected
            datos$estado_civil
datos$genero Casado Divorciado Soltero Viudo
   Femenino   13.78      10.07   22.26  6.89
   Masculino  12.22       8.93   19.74  6.11
  • ...$p.value: tenemos guardado el p-valor.
contraste$p.value
[1] 0.4305757

¿Cómo interpretar el contraste?

contraste

    Pearson's Chi-squared test

data:  datos$genero and datos$estado_civil
X-squared = 2.7573, df = 3, p-value = 0.4306

Como \(p.value = 0.4306 > \alpha = 0.05\), no podemos rechazar la hipótesis nula: no hay evidencias suficientes en la muestra para concluir que haya dependencia.

3.2.3 Inferencia cuali vs cuali: prueba de Fisher

Otra alternativa es el test exacto de Fisher, una prueba estadística utilizada para determinar si hay una asociación significativa entre dos variables cualitativas especialmente útil cuando las frecuencias esperadas son bajas y tenemos dos grupos en cada cualitativa (la tabla de frecuencias es \(2 \times 2\)). No entraremos en mucho detalle matemático pero usa la distribución real de una variable aleatoria que sigue lo que se conoce como distribución hipergeométrica.

 

Como curiosidad dicha prueba nació cuando Fisher trataba de comprobar si una compañera, Muriel Birstol, era capaz de detectar en un té con leche si se había añadido primero el té o la leche en su taza (y del experiemnto del que nació la regla del \(\alpha = 5%\)).

Para aplicarlo nos basta con usar fisher.test().

fisher.test(datos$genero, datos$estado_civil)

    Fisher's Exact Test for Count Data

data:  datos$genero and datos$estado_civil
p-value = 0.4462
alternative hypothesis: two.sided

3.2.4 Métricas de asociación

Como hemos dicho es especialmente útil cuando tenemos solo 2 modalidades en cada cualitativa ya nos proporciona métricas de asociación

Veamos un ejemplo con la tabla placebo_medicamento.csv

datos_placebo <- read_csv(file = "./datos/placebo_medicamento.csv")
Rows: 33 Columns: 3
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): grupo_tratamiento, observado
dbl (1): id_paciente

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
datos_placebo
# A tibble: 33 × 3
   id_paciente grupo_tratamiento observado
         <dbl> <chr>             <chr>    
 1           1 medicamento       mejora   
 2           2 medicamento       mejora   
 3           3 medicamento       mejora   
 4           4 medicamento       mejora   
 5           5 medicamento       mejora   
 6           6 medicamento       mejora   
 7           7 medicamento       mejora   
 8           8 medicamento       mejora   
 9           9 medicamento       mejora   
10          10 medicamento       mejora   
# ℹ 23 more rows
fisher.test(datos_placebo$observado, datos_placebo$grupo_tratamiento)

    Fisher's Exact Test for Count Data

data:  datos_placebo$observado and datos_placebo$grupo_tratamiento
p-value = 0.01336
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
  1.308438 57.326435
sample estimates:
odds ratio 
  7.386906 

Si te fijas ahora nos devuelve además un contraste de lo que se conoce como odds ratio (OR: razón de probabilidades)

alternative hypothesis: true odds ratio is not equal to 1

table(datos_placebo$observado, datos_placebo$grupo_tratamiento)
           
            medicamento placebo
  mejora             13       6
  no mejora           3      11

La interpretación de Odds ratio (OR) es cuantificar la asociación entre dos variables respecto a una asociación espúrea ¿Cuánto mejoran los que tomaron medicamento respecto a una posible mejora basal (aleatoria) del placebo?

  • Ratio de mejora en tratados: \(13/3 = 4.33333\)
  • Ratio de mejora en placebo: \(6/11 = 0.54545\)

\[OR = \frac{13/3}{6/11} = \frac{13*11}{6*3} = 7.94\]

Los pacientes sometidos a tratamiento mejoran 7.9 veces más si el placebo mejorase por azar.

 

Otra de las métricas habituales es la conocida como razón de prevalencias (Risk Ratio, RR) que nos proporciona un ratio entre la probabilidad de prevalencia de un evento en dos grupos.

  • Prevalencia de mejora en tratados: \(13/(3+13) = 0.8125\)
  • Prevalencia de mejora en placebo: \(6/(11+6) = 0.35294\)

\[RR = \frac{13/(3+13)}{6/(11+6)} = \frac{13*11}{6*3} = 2.30208\] Los pacientes sometidos a tratamiento tienen más del doble de «riesgo» de mejorar que los pacientes con placebo.

 

Ambas métricas podemos estimarlas también con el paquete {epitools}

library(epitools)
OR <- oddsratio(datos_placebo$observado, datos_placebo$grupo_tratamiento)
OR$measure
           odds ratio with 95% C.I.
Predictor   estimate    lower    upper
  mejora    1.000000       NA       NA
  no mejora 7.201088 1.553915 44.13078
  • Si \(OR = 1\) no hay asociación entre las variables.
  • Si \(OR > 1\) hay una asociación positiva, es decir, la exposición está asociada con un mayor riesgo.
  • Si \(OR < 1\) hay una asociación negativa, es decir, la exposición está asociada con un menor riesgo.
RR <- riskratio(datos_placebo$observado, datos_placebo$grupo_tratamiento)
RR$measure
           risk ratio with 95% C.I.
Predictor   estimate    lower    upper
  mejora    1.000000       NA       NA
  no mejora 2.488095 1.215737 5.092068
  • Si \(RR = 1\) no hay diferencias en el riesgo entre los grupos.
  • Si \(RR > 1\) el grupo expuesto (en este caso medicado) tiene mayor riesgo (en este caso de mejorar)
  • Si \(RR < 1\) el grupo expuesto tiene menor riesgo.

3.2.5 Gráficos

Volvamos al ejemplo de encuesta de satisfacción: vamos a intentar relacionar las dos variables cualitativas genero y estado_civil para complementar el análisis numérico realizado (amén del geom_tile() que hemos hecho para visualizar la tabla de frecuencias)

Sabemos realizar un diagrama de barras de cada una por separado, ¿cómo incluir la información de ambas con geom_bar() Piensa cómo hacerlo recordando que geom_bar() solo admite una coordenada x = ... o y = .... ¿Cómo incluir la info de otra variable que no sea en x o y?

Code
ggplot(datos) +
  geom_bar(aes(x = estado_civil, fill = genero), alpha = 0.6) +
  ggthemes::scale_fill_colorblind() +
  labs(x = "Estado civil", y = "Frec. absolutas",
       fill = "Género") +
  theme_minimal()

 

La función geom_bar() nos permite jugar un poco con el tipo de barras, que por defecto las muestra stacked (apiladas). Dicho ajuste podemos cambiarlo con el argumento position: si position = "dodge" las muestra de manera agrupada una detrás de otra.

Code
ggplot(datos) +
  geom_bar(aes(x = estado_civil, fill = genero),
           position = "dodge", alpha = 0.6) +
  ggthemes::scale_fill_colorblind() +
  labs(x = "Estado civil", y = "Frec. absolutas",
       fill = "Género") +
  theme_minimal()

La mejor opción para visualizar si hay asociación es que cada barra de estado civil representa el total y nos muestre el % de cada sexo en cada una: si fuesen independientes, el reparto por sexo en cada barra debería ser similar. Lo haremos con position = "fill"

Code
ggplot(datos) +
  geom_bar(aes(x = estado_civil, fill = genero),
           position = "fill", alpha = 0.6) +
  ggthemes::scale_fill_colorblind() +
  labs(x = "Estado civil", y = "Frec. relativas",
       fill = "Género") +
  theme_minimal()

Code
ggplot(datos) +
  geom_bar(aes(y = estado_civil, fill = genero),
           position = "fill", alpha = 0.6) +
  ggthemes::scale_fill_colorblind() +
  labs(x = "Estado civil", y = "Frec. relativas",
       fill = "Género") +
  theme_minimal()

3.3 💻 Tu turno

Intenta realizar los siguientes ejercicios sin mirar las soluciones

📝 Calcula las tablas de frecuencias absoluta y relativa con las variables genero y estado_salud

Code
tabla_freq <- table(datos$genero, datos$estado_salud)
prop.table(tabla_freq)
prop.table(tabla_freq, margin = 1)
prop.table(tabla_freq, margin = 2)

📝 Usando la tabla anterior:

  • ¿Qué porcentaje, de entre las mujeres, tiene un buen estado de salud?

  • ¿Qué porcentaje, de entre los hombres, tiene un estado de salud regular?

  • ¿Qué porcentaje de los que tienen estado de salud malo, son mujeres?

Code
# De entre las mujeres un 45.28% tiene un buen estado de salud
# De entre los hombres un 34.04% tiene un estado de salud regular
# Un 33.33% de los que tienen un estado de salud malo, son mujeres

📝 Realiza ambos contrastes e intenta razonar la respuesta a la pregunta: ¿están estas dos variables asociadas? ¿Existe algún tipo de dependencia entre ellas? Hazlo considerando \(\alpha = 0.05\).

Code
chisq.test(tabla_freq)$p.value
fisher.test(tabla_freq)$p.value

# En ambos casos p-value > alpha: no podemos rechazar la  hipótesis nula de independencia: no hay evidencias suficientes CON LA MUESTRA QUE TENEMOS para concluir que haya alguna asociación

📝 Las funciones chisq.test() y fisher.test() proporcionan un objeto htest que dentro contiene el p-valor (accediendo con $p.value dentr de él). ¿Cómo guardar ambos p-valores en una tabla resumen en tidyverse? Exporta los resultados a un .csv

Code
resumen_dependencia <-
  datos |> 
  summarise("sig_chisq" = chisq.test(genero, estado_civil)$p.value,
            "sig_fisher" = fisher.test(genero, estado_civil)$p.value)
write_csv(resumen_dependencia, file = "./datos/resumen_dependencia.csv")

4 🐣 Caso práctico I: placebo vs fármaco

4.1 Pregunta 1

Carga el fichero placebo_medicamento_completo.csv donde tenemos guardado los niveles de colesterol antes y después de un tratamiento: a 76 personas se les dio un medicamento para bajarlo y a 24 personas placebo.

Code
datos <- read_csv(file = "./datos/placebo_medicamento_completo.csv")
Rows: 100 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (1): tratamiento
dbl (3): id, colesterol_pre, colesterol_post

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

4.2 Pregunta 2

Añade una nueva variable dicotómica a los datos que nos guarde mejora si el paciente mejoró tras el tratamiento y no mejora en caso negativo

Code
datos <-
  datos |> 
  mutate("mejora" = if_else(colesterol_post <= colesterol_pre, "mejora",
                            "no mejora"))

4.3 Pregunta 3

Visualiza ambas variables (mejora y tratamiento) a la vez con un diagrama de barras de manera que podamos observar indicios de una posible independencia o dependencia entre ambas. Echa un vistazo a las diapositivas antes. Hazlo antes a papel y boli si lo necesitas

Code
# así pintaríamos en cada barra de tratamiento los mejora o no mejora
ggplot(datos) +
  geom_bar(aes(x = tratamiento, fill = mejora), alpha = 0.6) +
  ggthemes::scale_fill_colorblind() +
  theme_minimal()

# pero dado que tienes más tratados que del grupo control
# no permite comparar bien así que igualamos las barras
# para que cada barra sea el 100% de su categoría
ggplot(datos) +
  geom_bar(aes(x = tratamiento, fill = mejora), alpha = 0.6,
           position = "fill") +
  ggthemes::scale_fill_colorblind() +
  theme_minimal()

# Parece evidente visualmente que hay una diferencia entre mejora y no mejora
# en cada barra

4.4 Pregunta 4

Calcula la tabla de frecuencias absoluta y relativa que consideres necesarias para responder a las siguientes preguntas:

  1. ¿Cuántas personas de las tratadas con medicamento no mejoraron?

  2. ¿Qué de personas del total del estudio acabaron mejorando habiendo tomando placebo?

  3. ¿Qué % de personas tomó medicamentos entre los que no mejoraron?

  4. ¿Qué % de personas de los que tomaron medicamento mejoraron?

Code
table(datos$tratamiento, datos$mejora)
prop.table(table(datos$tratamiento, datos$mejora))
prop.table(table(datos$tratamiento, datos$mejora), margin = 1)
prop.table(table(datos$tratamiento, datos$mejora), margin = 2)
# 9 personas de las tratadas con medicamento no mejoraron
# 9% del total de personas mejoraron y tomaron placebo
# 37% de los que no mejoraron habían tomado la medicación
# 88.1% de los que tomaron medicamento mejoraron

4.5 Pregunta 5

Para confirmar y cuantificar las evidencias que ya tenemos, vamos a realizar un contraste de hipótesis. Realiza la prueba de chi-cuadrado e interpreta el resultado con \(\alpha = 0.05\).

Code
chisq.test(datos$tratamiento, datos$mejora)
# Dado que p-value = 1.654e-06 << alpha --> debemos rechazar la hipótesis nula -->
# hay evidencias suficientes para afirmar que hay relación de dependencia

4.6 Pregunta 6

Realiza la prueba de chi-cuadrado y Fisher e incluye los p-valores en una tabla resumen haciendo uso de tidyverse. Exporta a un .csv dicha tabla resumen

Code
resumen_pvalores <-
  datos |> 
  summarise("sig_chisq" = chisq.test(datos$tratamiento, datos$mejora)$p.value,
            "sig_fisher" = fisher.test(datos$tratamiento, datos$mejora)$p.value)
write_csv(resumen_pvalores, file = "./datos/resumen_pvalores.csv")

4.7 Pregunta 7

Realiza la prueba de Fisher y mira la salida completa. Interpreta la salida, no solo del contraste sino de los odd ratio.

Code
fisher.test(datos$tratamiento, datos$mejora)

    Fisher's Exact Test for Count Data

data:  datos$tratamiento and datos$mejora
p-value = 2.519e-06
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
  3.722458 42.096028
sample estimates:
odds ratio 
  11.95213 
Code
# OR estimado es de 11.95 --> al ser mayor que 1 implica que
# hay una asociación positiva entre las variables
# hay 12 veces más opciones de que te baje el colesterol si tomas el
# medicamento respecto a una posible mejora aleatoria (porque sí).

5 🐣 Caso práctico II: bronquitis y tabaco

Carga el archivo de datos fumadores.csv donde tenemos datos de 96 pacientes sobre sí o fuman y quienes han desarrollado o no bronquitis.

datos <- read_csv(file = "./datos/fumadores.csv")
Rows: 96 Columns: 3
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (2): fumador, estado
dbl (1): id

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
datos
# A tibble: 96 × 3
      id fumador estado    
   <dbl> <chr>   <chr>     
 1     1 sí      bronquitis
 2     2 sí      bronquitis
 3     3 sí      bronquitis
 4     4 sí      bronquitis
 5     5 sí      bronquitis
 6     6 sí      bronquitis
 7     7 sí      bronquitis
 8     8 sí      bronquitis
 9     9 sí      bronquitis
10    10 sí      bronquitis
# ℹ 86 more rows

5.1 Pregunta 1

Realiza la tabla de contigencia de manera absoluta y relativa y responde a las siguientes preguntas

  1. ¿Cuántas personas fumaoras tienen bronquitis?

  2. ¿Qué % de los fumadores está sano?

  3. ¿Qué % del total son a la vez no fumadores y enfermos de bronquitis?

  4. ¿Qué % de los enfermos son fumadores?

Code
table(datos$fumador, datos$estado)
prop.table(table(datos$fumador, datos$estado))
prop.table(table(datos$fumador, datos$estado), margin = 1)
prop.table(table(datos$fumador, datos$estado), margin = 2)
# a) 32 personas
# b) 38.46%
# c) 16%
# d) 61.53%

5.2 Pregunta 2

Visualiza ambas variables a la vez de manera adecuada que nos permita comparar

Code
ggplot(datos) +
  geom_bar(aes(x = fumador, fill = estado), alpha = 0.6, position = "fill") +
  labs(x = "fumador", y = "Frec relativa", fill = "Estado") +
  theme_minimal()

5.3 Pregunta 3

¿Existen evidencias en la muestra de una asociación entre ambas variables?

Code
datos |> 
  summarise("sig_chisq" = chisq.test(datos$fumador, datos$estado)$p.value,
            "sig_fisher" = fisher.test(datos$fumador, datos$estado)$p.value)
# p-valor < alpha --> hay evidencias para rechazar la hip nula
# hay evidencias (no muy fuertes, quizás aumentar tamaño muestral?) de
# que las variables son dependientes y existe una asociación

5.4 Pregunta 4

Si hubiera asociación, cuantifica la fuerza de dicha asociación (y el sentido) y calcula el riesgo relativo de los fumadores a contraer bronquitis (respecto a no fumadores)

Code
fisher.test(datos$fumador, datos$estado)
# OR estimado = 0.3611 ==> piensa que tenemos no fumar primero y luego fumar ==>
# 1/0.3611 = 2.769316 > 1 ==> hay una asociación positiva entre fumar y tener 
# bronquitis 
# La bronquitis en pacientes que fuman es 2.77 veces más frecuente
# que en los pacientes que no fuman

# RR ratio
a <- 32  # Expuestos con evento
b <- 16  # Expuestos sin evento
c <- 20  # No expuestos con evento
d <- 28  # No expuestos sin evento

RR <- (a / (a + b)) / (c / (c + d))
# El grupo que fuma tiene un riesgo 1.6 veces mayor de que desarrollar bronquitis en comparación con el grupo que no fuma.

6 🐣 Caso práctico III: salud mental

Esta la base de datos datos_salud_mental.csv tenemos información recopilada de 100 pacientes que acuden a un centro de salud mental. Se quiere realizar un estudio para ver el impacto que tienen distintas características sobre la ansiedad y depresión en estos 100 pacientes. Los datos incluyen una variedad de variables relacionadas con la salud mental, así como características demográficas y de estilo de vida.

6.1 Pregunta 1

Carga la base de datos y normaliza los nombres de las variables

Code
datos <-
  read_csv(file = "./datos/datos_salud_mental.csv") |> 
  janitor::clean_names()
Rows: 100 Columns: 10
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Genero, UsoDrogasRecreativas, TipoDrogas
dbl (7): ID, Edad, Ansiedad, Depresion, SesionesTerapia, ActividadFisica, Ho...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

6.2 Pregunta 2

Las variables son:

  • id: identificador único del paciente.
  • edad: edad del paciente en años.
  • Genero: género del paciente.
  • ansiedad: nivel de ansiedad del paciente en una escala del 1 al 10.
  • depresión: nivel de depresión del paciente en una escala del 1 al 10.
  • sesiones_terapia: número de sesiones de terapia asistidas en el último año.
  • actividad_fisica: número de días a la semana que el paciente realiza actividad física.
  • horas_sueno: número de horas promedio de sueño por noche.
  • uso_drogas_recreativas: indicador de si el paciente ha usado drogas recreativas en el último año.
  • tipo_drogas: tipo de drogas que ha consumido el paciente.

¿De qué tipo es cada variable? Convierte las que consideres a cualis nominales y a cualis ordinales, y si hay alguna variable que deba ser lógica

Code
# id: en realidad esto tendría ser un factor (un texto) ya que no cuenta nada
# Cuantitativas: edad, horas_sueno
# Cualitativas nominales: genero, tipo_drogas
# Cuanitativas discretas: sesiones_terapia y actividad_fisica
# Cuantitativas discretas pero que deberíamos tratarlas como cualis ordinales
# ya que son escalas: ansiedad, depresión
# Binarias (cualis ordinales muy concretas): uso_drogas_recreativas
datos <-
  datos |> 
  mutate("id" = as.character(id),
         "genero" = factor(genero), "tipo_drogas" = factor(tipo_drogas),
         "ansiedad" = factor(ansiedad, levels = as.character(1:10), ordered = TRUE),
         "depresion" = factor(depresion, levels = as.character(1:10), ordered = TRUE),
         "uso_drogas_recreativas" = (uso_drogas_recreativas == "Si"))

6.3 Pregunta 3

Calcula la tabla de frecuencias absolutas y relativas de género.

Code
tabla_freq_abs <- table(datos$genero)
tabla_freq_rel <- prop.table(tabla_freq_abs)

6.4 Pregunta 4

Calcula la media de las 4 variables cuantitativas que tenemos desagregado por género. Exporta dicho resumen en un .csv

Code
resumen <- 
  datos |> 
  drop_na(where(is.numeric)) |> 
  summarise(across(where(is.numeric), mean), .by = genero)
write_csv(resumen, file = "./datos/resumen.csv")

6.5 Pregunta 5

Calcula la tabla de contigencia de las variables ansiedad vs genero. Calcula otra para ansiedad vs depresion. Usa useNA = "always" como argumento para incluir los NA

Code
tabla_freq_genero_ansiedad <- table(datos$genero, datos$ansiedad, useNA = "always")
tabla_freq_depresion_ansiedad <- table(datos$depresion, datos$ansiedad, useNA = "always")

6.6 Pregunta 6

Realiza un gráfico adecuado para la variable edad. Piensa como adaptarlo para tenerlo desagregado por genero.

Code
# Densidades
ggplot(datos) +
  geom_density(aes(x = edad), fill = "#459191", alpha = 0.4) +
  labs(x = "Edad (años)", y = "Densidad (frec relativa)") +
  theme_minimal()

library(ggridges)
ggplot(datos) +
  geom_density_ridges(aes(x = edad, y = genero, fill = genero), alpha = 0.4) +
  ggthemes::scale_fill_colorblind() +
  labs(x = "Edad (años)", y = "Sexo", fill = "Género") +
  theme_minimal()

# Histograma (mala idea con pocos datos)
ggplot(datos) +
  geom_histogram(aes(x = edad), bins = 15, fill = "#459191", alpha = 0.4) +
  labs(x = "Edad (años)", y = "Frec absoluta") +
  theme_minimal()
ggplot(datos) +
    geom_histogram(aes(x = edad, fill = genero), bins = 15, alpha = 0.25) +
    labs(x = "Edad (años)", y = "Frec absoluta") +
    theme_minimal()

# Boxplot
ggplot(datos) +
  geom_boxplot(aes(y = edad), fill = "#459191", alpha = 0.4,
               outlier.size = 3, outlier.alpha = 0.9,
               outlier.color = "#991293", outlier.shape = 18) +
  labs(y = "Edad") +
  theme_minimal()

ggplot(datos, aes(x = genero, y = edad, fill = genero, color = genero)) +
  geom_boxplot(alpha = 0.4, outlier.size = 3, outlier.alpha = 0.9,
               outlier.color = "#991293", outlier.shape = 18) +
  ggthemes::scale_color_colorblind() +
  ggthemes::scale_fill_colorblind() +
  guides(color = "none") +
  labs(x = "Género", y = "Edad", fill = "Género") +
  theme_minimal()

6.7 Pregunta 7

Intenta programar el código que necesitarías para obtener los tres gráfico inferiores. Intenta imitarlos al máximo.

Code
ggplot(datos) +
  geom_bar(aes(y = ansiedad), fill = "#991293", alpha = 0.5) +
  labs(x = "Frecuencia absoluta", y = "Ansiedad (escala 1 a 10)") +
  theme_minimal()

Code
ggplot(datos) +
  geom_bar(aes(y = ansiedad, fill = genero), alpha = 0.5) +
  ggthemes::scale_fill_colorblind() +
  labs(x = "Frecuencia absoluta", y = "Ansiedad (escala 1 a 10)",
       fill = "Género") +
  theme_minimal()

Code
ggplot(datos) +
  geom_bar(aes(y = ansiedad, fill = genero), alpha = 0.5, position = "fill") +
  ggthemes::scale_fill_colorblind() +
  labs(x = "Frecuencia relativa", y = "Ansiedad (escala 1 a 10)",
       fill = "Género") +
  theme_minimal()

6.8 Pregunta 8

Realiza un gráfico adecuado para visualizar a la vez depresión y ansiedad.

Code
# fíjate que aunque sean números, dado que son variables discretas
# de una escala, no permite una correcta visualización un diagrama
# de dispersión ya que hay muchos puntos iguales que se solapan
ggplot(datos) + 
  geom_point(aes(x = depresion, y = ansiedad)) +
  theme_minimal()

# una opción: se ve un patrón (tipo "recta ascedente")
ggplot(datos |> count(depresion, ansiedad)) + 
  geom_point(aes(x = depresion, y = ansiedad, color = n, size = n)) +
  scale_color_viridis_c() +
  guides(size = "none") +
  theme_minimal()

6.9 Pregunta 9

¿Existe asociación entre genero y uso de drogas? ¿Y entre depresión y ansiedad? Cuantifica la respuesta todo lo que puedas.

Code
resumen_p_valores_1 <-
  datos |> 
  summarise("sig_chisq" = chisq.test(datos$genero, datos$uso_drogas_recreativas)$p.value,
            "sig_fisher" = fisher.test(datos$genero, datos$uso_drogas_recreativas)$p.value)
Warning: There was 1 warning in `summarise()`.
ℹ In argument: `sig_chisq = chisq.test(datos$genero,
  datos$uso_drogas_recreativas)$p.value`.
Caused by warning in `chisq.test()`:
! Chi-squared approximation may be incorrect
Code
# p-valores >> alpha --> no evidencias para rechazar la independencia -->
# no hay evidencias para afirmar la dependencia

# con tantas categorías Fisher no funciona
chisq.test(datos$depresion, datos$ansiedad)
Warning in chisq.test(datos$depresion, datos$ansiedad): Chi-squared
approximation may be incorrect

    Pearson's Chi-squared test

data:  datos$depresion and datos$ansiedad
X-squared = 174.39, df = 63, p-value = 2.148e-12
Code
# p-valores << alpha --> sí hay evidencias para rechazar la independencia -->
# sí hay evidencias para afirmar la dependencia