1 Introducción y Objetivos de Aprendizaje

La Distribución Normal o Gaussiana es el pilar fundamental de la bioestadística paramétrica y la herramienta analítica esencial para la modelación de variables fisiológicas y biológicas continuas.

En este tutorial consolidaremos:

  1. La formalización matemática y la geometría de la distribución normal \(N(\mu, \sigma)\).
  2. La estandarización o tipificación mediante puntajes \(Z\), traduciendo la fórmula matemática a código R vectorizado.
  3. El cálculo de probabilidades acumuladas mediante tres métodos: Tablas \(Z\) manuales (“old school”), funciones nativas de R (pnorm) y simuladores web interactivos (Shiny).
  4. Escenarios reales de aplicación en Farmacocinética (PK) y Farmacodinámica (PD).
  5. Métodos gráficos (Histogramas y Q-Q Plots) y analíticos (Prueba de Shapiro-Wilk) para evaluar el supuesto de normalidad.
  6. Guía para la Tarea Autónoma Grupal basada en tus propios proyectos de investigación.

2 Fundamentos Teóricos de la Distribución Normal y Estandarización

2.1 La Función de Densidad Normal \(N(\mu, \sigma)\)

Una variable aleatoria continua \(X\) sigue una Distribución Normal con media poblacional \(\mu\) y desviación estándar \(\sigma\) (\(X \sim N(\mu, \sigma)\)) si su función de densidad de probabilidad está dada por:

\[f(x) = \frac{1}{\sigma \sqrt{2\pi}} \exp\left( -\frac{1}{2} \left( \frac{x - \mu}{\sigma} \right)^2 \right), \quad -\infty < x < \infty\]

2.1.1 Propiedades Clave:

  • Simetría Axial: La curva es perfectamente simétrica respecto a su eje central \(x = \mu\).
  • Coincidencia de la Tríada Central: Media, Mediana y Moda son estrictamente iguales (\(\mu = Me = Mo\)).
  • Área Bajo la Curva: El área total comprendida bajo \(f(x)\) es exactamente \(1.00\) (o \(100\%\)).
  • Puntos de Inflexión: Ocurren exactamente a una desviación estándar del centro: \(x = \mu \pm 1\sigma\).

2.2 La Transformación \(Z\) (Estandarización)

Para comparar variables medidas en distintas unidades físicas (ej. Colesterol en \(\text{mg/dL}\) frente a Presión Arterial en \(\text{mmHg}\)), transformamos la variable \(X \sim N(\mu, \sigma)\) en una Distribución Normal Estándar \(Z \sim N(0, 1)\) mediante la ecuación:

\[Z = \frac{X - \mu}{\sigma}\]

2.2.1 Propiedades Físico-Matemáticas de \(Z\):

  1. Centrado (\(-\mu\)): Al restar \(\mu\), se desplaza la distribución horizontalmente hasta ubicar el centro de masa en el origen (\(\mu_Z = 0\)).
  2. Escalamiento (\(/\sigma\)): Al dividir entre \(\sigma\), se reescala la variabilidad a la unidad (\(\sigma_Z = 1\)).
  3. Adimensionalidad: El puntaje \(Z\) expresa la distancia exacta (en número de desviaciones estándar) a la que se sitúa una observación \(X\) respecto a su media.

2.3 Traducción a Código R Vectorizado

En R, podemos implementar la fórmula de estandarización aprovechando la vectorización nativa o utilizando la función incorporada scale().

2.3.1 Implementación Manual Vectorizada:

# Función personalizada vectorizada para calcular Puntajes Z
calcular_puntaje_z <- function(x, mu = NULL, sigma = NULL) {
  if (is.null(mu)) mu <- mean(x, na.rm = TRUE)
  if (is.null(sigma)) sigma <- sd(x, na.rm = TRUE)
  
  z <- (x - mu) / sigma
  return(z)
}

# Ejemplo práctico con un vector de concentraciones de Colesterol (mg/dL)
colesterol_obs <- c(165, 180, 200, 235, 270, 305)
mu_poblacion   <- 200
sigma_poblacion <- 35

# Cálculo vectorizado directo
z_colesterol <- calcular_puntaje_z(colesterol_obs, mu = mu_poblacion, sigma = sigma_poblacion)

# Crear DataFrame comparativo
data.frame(
  Colesterol_mg_dL = colesterol_obs,
  Diferencia_Media = colesterol_obs - mu_poblacion,
  Puntaje_Z = z_colesterol,
  Z_scale_R = as.numeric(scale(colesterol_obs, center = mu_poblacion, scale = sigma_poblacion))
)

2.4 Tres Métodos para Encontrar Probabilidades Acumuladas

2.4.1 Método 1: Búsqueda en Tablas de Distribución Normal \(N(0, 1)\) (“Old School”)

La tabla \(Z\) proporciona el área acumulada a la izquierda de un valor \(z\): \(P(Z \le z)\).

  • Caso 1: Cola Inferior (\(P(Z \le z)\)): Lectura directa de la tabla en la intersección de la fila \(z\) y la columna del segundo decimal.
  • Caso 2: Cola Superior (\(P(Z > z)\)): Se aplica la Regla del Complemento: \[P(Z > z) = 1 - P(Z \le z)\]
  • Caso 3: Intervalo Central (\(P(z_1 \le Z \le z_2)\)): Se resta el área menor del área mayor: \[P(z_1 \le Z \le z_2) = P(Z \le z_2) - P(Z \le z_1)\]

2.4.2 Método 2: Funciones Nativas de R (pnorm, qnorm, rnorm, dnorm)

R provee una familia de 4 funciones para la distribución normal:

Función Descripción Ejemplo
pnorm(q, mean, sd) Calcula la probabilidad acumulada \(P(X \le q)\) pnorm(270, mean=200, sd=35) \(\rightarrow 0.9772\)
qnorm(p, mean, sd) Devuelve el valor numérico (cuantil) para una probabilidad \(p\) qnorm(0.9772, mean=200, sd=35) \(\rightarrow 270\)
dnorm(x, mean, sd) Calcula la altura de la función de densidad \(f(x)\) dnorm(200, mean=200, sd=35)
rnorm(n, mean, sd) Genera \(n\) observaciones aleatorias de \(N(\mu, \sigma)\) rnorm(100, mean=200, sd=35)
# 1. Probabilidad acumulada a la izquierda de Z = +2.00
prob_izquierda <- pnorm(2.00, mean = 0, sd = 1)
cat("P(Z <= +2.00) =", round(prob_izquierda, 4), "\n")
## P(Z <= +2.00) = 0.9772
# 2. Cola superior (Regla del complemento en R)
prob_derecha <- pnorm(2.00, mean = 0, sd = 1, lower.tail = FALSE)
cat("P(Z > +2.00)  =", round(prob_derecha, 4), "\n")
## P(Z > +2.00)  = 0.0228
# 3. Intervalo central entre Z1 = -1.33 y Z2 = +1.67
prob_intervalo <- pnorm(1.67) - pnorm(-1.33)
cat("P(-1.33 <= Z <= +1.67) =", round(prob_intervalo, 4), "\n")
## P(-1.33 <= Z <= +1.67) = 0.8608

2.4.3 Método 3: Simuladores Web Interactivos (Shiny Apps)

Para la exploración visual dinámica en clases o autoestudio, se recomienda utilizar simuladores web interactivos de distribuciones continuas, tales como la aplicación Shiny de RStudio Gallery:

  • Enlace directo al simulador: Distributions Calculator (Shinyapps.io)
  • Instrucciones de uso:
    1. Seleccionar la distribución Normal.
    2. Ajustar \(\mu = 0\) y \(\sigma = 1\) (o los parámetros físicos originales \(\mu\) y \(\sigma\)).
    3. Elegir el tipo de región de interés: Lower tail (\(P(X \le x)\)), Upper tail (\(P(X > x)\)) o Both tails.
    4. Observar el sombreado automático del área bajo la curva y verificar el resultado numérico exacto.

3 Escenarios de Aplicación en Farmacología Básica

3.1 Escenario 1: Farmacocinética (PK) — Equiparabilidad del Aclaramiento Organospecífico

A dos pacientes con falla multiorgánica se les mide el aclaramiento de dos fármacos esenciales:

  • Fármaco A (Eliminación Hepática CYP3A4): \(CL_A \sim N(\mu = 450, \sigma = 60) \text{ mL/min}\). Valor observado: \(CL_A = 330 \text{ mL/min}\).
  • Fármaco B (Excreción Renal TFG-dependiente): \(CL_B \sim N(\mu = 110, \sigma = 15) \text{ mL/min}\). Valor observado: \(CL_B = 80 \text{ mL/min}\).

3.1.1 Estandarización y Visualización Lado a Lado:

# Parámetros Paciente A
mu_A <- 450; sigma_A <- 60; x_A <- 330
z_A <- (x_A - mu_A) / sigma_A

# Parámetros Paciente B
mu_B <- 110; sigma_B <- 15; x_B <- 80
z_B <- (x_B - mu_B) / sigma_B

# Graficar Paciente A
df_A <- data.frame(x = seq(mu_A - 4*sigma_A, mu_A + 4*sigma_A, length.out = 500)) %>%
  mutate(densidad = dnorm(x, mu_A, sigma_A))

p_A <- ggplot(df_A, aes(x = x, y = densidad)) +
  geom_area(data = filter(df_A, x <= x_A), fill = "#1D3557", alpha = 0.3) +
  geom_line(color = "#1D3557", size = 1.2) +
  geom_vline(xintercept = x_A, color = "#E76F51", size = 1.2) +
  scale_x_continuous(breaks = c(270, 330, 390, 450, 510, 570),
                     labels = c("270\n(-3σ)", "330\n(-2σ)", "390\n(-1σ)", "450\n(μ)", "510\n(+1σ)", "570\n(+2σ)")) +
  labs(title = "Fármaco A: Aclaramiento Hepático",
       subtitle = paste0("CL = 330 mL/min -> Z = ", sprintf("%.2f", z_A), " (Percentil 2.3%)"),
       x = "Aclaramiento (mL/min)", y = "f(x)") +
  theme_minimal()

# Graficar Paciente B
df_B <- data.frame(x = seq(mu_B - 4*sigma_B, mu_B + 4*sigma_B, length.out = 500)) %>%
  mutate(densidad = dnorm(x, mu_B, sigma_B))

p_B <- ggplot(df_B, aes(x = x, y = densidad)) +
  geom_area(data = filter(df_B, x <= x_B), fill = "#2A9D8F", alpha = 0.3) +
  geom_line(color = "#2A9D8F", size = 1.2) +
  geom_vline(xintercept = x_B, color = "#E76F51", size = 1.2) +
  scale_x_continuous(breaks = c(65, 80, 95, 110, 125, 140),
                     labels = c("65\n(-3σ)", "80\n(-2σ)", "95\n(-1σ)", "110\n(μ)", "125\n(+1σ)", "140\n(+2σ)")) +
  labs(title = "Fármaco B: Aclaramiento Renal",
       subtitle = paste0("CL = 80 mL/min -> Z = ", sprintf("%.2f", z_B), " (Percentil 2.3%)"),
       x = "Aclaramiento (mL/min)", y = "f(x)") +
  theme_minimal()

# Ensamble con patchwork
p_A + p_B + plot_annotation(title = "Equiparabilidad Clínica PK mediante Tipificación Z")

3.1.2 Decisión Posológica:

Aunque la pérdida absoluta en \(\text{mL/min}\) es muy diferente (\(-120 \text{ mL/min}\) vs. \(-30 \text{ mL/min}\)), la tipificación demuestra que ambos órganos sufren la misma gravedad relativa (\(Z = -2.00\)).

En la práctica clínica estandarizada, al caer en la zona crítica (\(Z \le -2.00\)), se aplica la regla de ajuste posológico empírico de reducir al \(50\%\) la dosis de mantenimiento (\(D_m = C_{ss} \times CL\)) para ambos fármacos, previniendo la acumulación tóxica.


3.2 Escenario 2: Farmacodinámica (PD) — Interacciones Medicamentosas y Ventana Terapéutica

Evaluamos la concentración plasmática de Digoxina (\(C_p\)) y el umbral arritmogénico de cardiotoxicidad (\(C_{tox} = 2.1 \text{ ng/mL}\)):

  1. Monoterapia Estándar: \(C_p \sim N(\mu = 1.2, \sigma = 0.3) \text{ ng/mL}\). \[Z_{tox} = \frac{2.1 - 1.2}{0.3} = +3.00 \implies P(C_p > 2.1) = P(Z > +3) \approx \mathbf{0.13\%}\]
  2. Coadministración con Amiodarona (Inhibición de P-gp): Mantiene la misma media pero incrementa la variabilidad biológica a \(\sigma' = 0.45 \text{ ng/mL}\). \[Z_{tox}' = \frac{2.1 - 1.2}{0.45} = +2.00 \implies P(C_p > 2.1) = P(Z > +2) \approx \mathbf{2.28\%}\]
z_std  <- (2.1 - 1.2) / 0.30
z_amio <- (2.1 - 1.2) / 0.45

p_tox_std  <- pnorm(z_std, lower.tail = FALSE)
p_tox_amio <- pnorm(z_amio, lower.tail = FALSE)

cat("Riesgo de Toxicidad en Monoterapia :", round(p_tox_std * 100, 2), "%\n")
## Riesgo de Toxicidad en Monoterapia : 0.13 %
cat("Riesgo de Toxicidad con Amiodarona:", round(p_tox_amio * 100, 2), "%\n")
## Riesgo de Toxicidad con Amiodarona: 2.28 %
cat("Factor de Incremento de Riesgo     :", round(p_tox_amio / p_tox_std, 1), "veces\n")
## Factor de Incremento de Riesgo     : 16.9 veces

Conclusión PD: El aumento de la variabilidad biológica (\(\sigma\)) reduce el margen de seguridad \(Z\), multiplicando por 18 veces el riesgo de arritmias ventriculares graves.


4 Evaluación y Detección de Normalidad en Variables Continuas

Antes de aplicar pruebas paramétricas (ej. prueba \(t\) de Student, ANOVA o Regresión Lineal), es obligatorio verificar si los datos cumplen el supuesto de normalidad.


4.1 Métodos Gráficos: Histograma y Normal Q-Q Plot

El Q-Q Plot (Quantile-Quantile Plot) grafica los cuantiles observados de la muestra frente a los cuantiles teóricos de una distribución normal \(N(0, 1)\).

4.1.1 Las 4 Geometrías Diagnósticas del Q-Q Plot:

set.seed(2026)
n <- 200

# 1. Normalidad
x_norm <- rnorm(n, mean = 100, sd = 15)

# 2. Colas Pesadas / Leptocurtosis (t-Student df=3)
x_heavy <- 100 + 15 * (rt(n, df = 3) / sqrt(3))

# 3. Asimetría Positiva (Lognormal -> Plátano / "U")
x_pos <- rlnorm(n, meanlog = log(8), sdlog = 0.45)

# 4. Asimetría Negativa (Beta -> Plátano Invertido / "U" Invertida)
x_neg <- 120 * rbeta(n, shape1 = 6.5, shape2 = 1.8)

# Función auxiliar para graficar
crear_panel_qq <- function(datos, titulo, etiqueta_qq) {
  df <- data.frame(x = datos)
  
  p1 <- ggplot(df, aes(x = x)) +
    geom_histogram(aes(y = ..density..), bins = 15, fill = "#1D3557", color = "white", alpha = 0.7) +
    geom_density(color = "#2A9D8F", size = 1) +
    labs(title = titulo, x = "Valor Observado", y = "Densidad") +
    theme_minimal()
  
  p2 <- ggplot(df, aes(sample = x)) +
    stat_qq_line(color = "#E76F51", size = 1) +
    stat_qq(color = "#1D3557", alpha = 0.7) +
    labs(title = "Normal Q-Q Plot", subtitle = etiqueta_qq, x = "Cuantiles Teóricos (Z)", y = "Cuantiles Muestrales") +
    theme_minimal()
  
  return(p1 + p2)
}

(crear_panel_qq(x_norm, "1. Distribución Normal Perfecta", "Puntos alineados sobre la recta 45°") /
 crear_panel_qq(x_heavy, "2. Colas Pesadas / Outliers", "Patrón en 'S' (Sigmoidal)") /
 crear_panel_qq(x_pos, "3. Asimetría Positiva (Sesgo Derecha)", "Patrón en 'U' / Plátano (Convexo)") /
 crear_panel_qq(x_neg, "4. Asimetría Negativa (Sesgo Izquierda)", "Patrón 'Plátano Invertido' (Cóncavo)"))


4.2 Pruebas de Hipótesis Formales: Test de Shapiro-Wilk

Complementamos el diagnóstico visual con la prueba analítica de Shapiro-Wilk (shapiro.test() en R):

\[\begin{cases} H_0: \text{La variable sigue una Distribución Normal.} \\ H_1: \text{La variable NO sigue una Distribución Normal.} \end{cases}\]

  • Regla de Decisión:
    • Si \(p\text{-valor} > 0.05 \implies\) No se rechaza \(H_0\) (se asume normalidad).
    • Si \(p\text{-valor} \le 0.05 \implies\) Se rechaza \(H_0\) (los datos no son normales; usar estadística no paramétrica o transformar con \(\ln X\)).
# Evaluación analítica de los 4 escenarios simulados
shapiro_resultados <- data.frame(
  Escenario = c("Normal", "Colas Pesadas", "Asimetría Positiva", "Asimetría Negativa"),
  Estadistico_W = c(shapiro.test(x_norm)$statistic,
                    shapiro.test(x_heavy)$statistic,
                    shapiro.test(x_pos)$statistic,
                    shapiro.test(x_neg)$statistic),
  p_valor = c(shapiro.test(x_norm)$p.value,
              shapiro.test(x_heavy)$p.value,
              shapiro.test(x_pos)$p.value,
              shapiro.test(x_neg)$p.value)
) %>%
  mutate(Conclusion_Alpha_0.05 = ifelse(p_valor > 0.05, "Asumir Normalidad (No rechazar H0)", "No Normal (Rechazar H0)"))

shapiro_resultados

5 Tarea Autónoma Grupal: Evaluación de Normalidad en Proyectos de Investigación

5.1 Objetivos de la Actividad

Cada equipo de trabajo deberá aplicar el flujo metodológico completo (exploratorio, gráfico y analítico) para evaluar la distribución de las variables continuas pertenecientes a su base de datos del proyecto de investigación.


5.2 Instrucciones y Entregable

  1. Selección de Variables: Identificar al menos dos (2) variables continuas en su dataset de investigación (ej. IMC, Presión Arterial, Colesterol, Días de Estancia, Niveles de Biomarcadores).
  2. Generación del Script en RMarkdown:
    • Calcular las medidas de tendencia central (Media, Mediana) y dispersión (Desviación Estándar, Rango Intercuartílico).
    • Estandarizar una de las variables seleccionadas calculando los puntajes \(Z\) para cada paciente e identificar valores atípicos (\(|Z| > 3.00\)).
    • Construir para cada variable el panel doble (Histograma con curva de densidad + Normal Q-Q Plot) utilizando ggplot2 y patchwork.
    • Ejecutar la prueba de Shapiro-Wilk (shapiro.test()).
  3. Redacción del Diagnóstico Biomédico:
    • Describir el patrón gráfico observado en el Q-Q Plot (¿Línea recta, “S”, “U” / Plátano, o “U” Invertida / Plátano Invertido?).
    • Justificar si la variable cumple o no el supuesto de normalidad basándose en el p-valor.
    • Concluir qué tipo de pruebas de hipótesis (Paramétricas como \(t\)-Student/ANOVA vs. No Paramétricas como Mann-Whitney/Kruskal-Wallis) deberán utilizar en sus informes finales.

5.3 Rúbrica de Evaluación Grupal (100 Puntos)

Criterio Excelente (100%) Satisfactorio (75%) Necesita Mejora (50%)
Estandarización Z (25 pts) Calcula e interpreta los puntajes \(Z\) de forma vectorizada e identifica correctamente los outliers. Calcula puntajes \(Z\) pero omite la interpretación del percentil o identificación de outliers. Errores en la fórmula o en la ejecución del código R.
Panel Gráfico (25 pts) Presenta Histogramas y Q-Q Plots perfectamente diagramados con etiquetas claras y estética cuidada. Presenta los gráficos pero faltan curvas de densidad o títulos explicativos. Gráficos incompletos, ilegibles o sin formato.
Prueba de Shapiro-Wilk (25 pts) Ejecuta shapiro.test(), reporta estadístico \(W\), \(p\)-valor y contrasta formalmente \(H_0\) vs \(H_1\). Presenta el \(p\)-valor pero no explicita las hipótesis ni la regla de decisión. Omite la prueba formal o interpreta al revés el \(p\)-valor.
Diagnóstico Biomédico (25 pts) Diagnostica correctamente la geometría del Q-Q Plot y justifica la elección de pruebas paramétricas o no paramétricas. Diagnóstico gráfico correcto pero indecisión sobre qué prueba estadística utilizar posteriormente. Diagnóstico erróneo de la distribución de los datos.

Cátedra de Bioestadística Médica — RMarkdown Tutorial compilado exitosamente.