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:
pnorm) y simuladores web interactivos
(Shiny).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\]
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}\]
En R, podemos implementar la fórmula de estandarización aprovechando
la vectorización nativa o utilizando la función
incorporada scale().
# 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))
)La tabla \(Z\) proporciona el área acumulada a la izquierda de un valor \(z\): \(P(Z \le z)\).
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
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:
A dos pacientes con falla multiorgánica se les mide el aclaramiento de dos fármacos esenciales:
# 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")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.
Evaluamos la concentración plasmática de Digoxina (\(C_p\)) y el umbral arritmogénico de cardiotoxicidad (\(C_{tox} = 2.1 \text{ ng/mL}\)):
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 %
## Riesgo de Toxicidad con Amiodarona: 2.28 %
## 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.
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.
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)\).
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)"))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}\]
# 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_resultadosCada 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.
ggplot2 y patchwork.shapiro.test()).| 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.