Estadística
Paquetes R para inferencia, descriptiva y visualización estadística
Sobre estadística en R
R nació como lenguaje estadístico antes que como lenguaje de programación de uso general, y eso se nota: el grueso de la estadística clásica está disponible en la base del lenguaje. stats::lm, stats::glm, stats::t.test, stats::aov, stats::cor.test, stats::wilcox.test cubren la mayor parte de lo que se necesita en un proyecto medio. Antes de añadir paquetes, conviene tener interiorizada esa API base: la mayoría de wrappers de “estadística tidy” devuelven al final un objeto que sigue heredando de lm o htest.
Sobre esa base se han construido tres capas que esta página cataloga:
- Capa descriptiva. Resúmenes de cohorte, “tabla uno” en publicaciones clínicas, summary statistics por grupo. Aquí entra
tableone(clínico) y, fuera de esta página, alternativas comogtsummary,arsenal::tablebyoskimr. - Capa de interpretación. Tamaños del efecto y sus intervalos de confianza, la métrica que realmente comunica magnitud, frente a los p-values que solo comunican evidencia contra el nulo.
effectsizey el resto del ecosistemaeasystats(parameters,performance,report) viven aquí. - Capa pedagógica e inferencial moderna. Inferencia basada en simulación/permutación con sintaxis tidy:
infer. Más cercana al razonamiento estadístico que a un wrapper de tests. - Capa de comunicación visual. Gráficos con resultados estadísticos integrados, sin pegar p-values a mano:
ggstatsplot.
Decisión recurrente al elegir herramienta: ¿necesito un modelo (stats::lm y derivados, lme4, nlme, brms), un resumen de cohorte (tableone, gtsummary), una métrica de impacto (effectsize), o un test puntual con sintaxis tidy (infer, rstatix)? Cada paquete de esta página resuelve uno de esos huecos. Rara vez se sustituyen entre sí.
El orden refleja jerarquía conceptual: primero descriptiva (tableone), después interpretación de modelos (effectsize), luego marco inferencial completo (infer), y al final el envoltorio de visualización (ggstatsplot).
tableone
tableone resuelve un problema muy concreto y muy frecuente en investigación clínica y epidemiológica: producir la Tabla 1 de un manuscrito, el resumen de características de la cohorte estratificado por grupo, con tests bivariantes opcionales. Su autor, Kazuki Yoshida, lo escribió pensando en publicaciones médicas, y esa orientación se nota en cada decisión por defecto (variables categóricas con conteos y porcentajes, continuas con media ± SD o mediana [IQR], tests apropiados según distribución).
No es una librería de modelado. Es una librería de presentación de descriptiva. Su salida está pensada para ir al portapapeles o a un Word/LaTeX casi sin retoques.
Cuándo usarlo
- Estudios clínicos, epidemiológicos o de cohorte que requieran una Table 1 estratificada por grupo (tratamiento vs control, expuesto vs no expuesto).
- Cuando el destino final es un manuscrito en formato académico clásico y quieres una salida limpia con SMD (standardized mean difference), útil en propensity score analyses.
Cuándo NO usarlo
- Reporting moderno con flexibilidad de formato.
gtsummaryestá mejor mantenido, tiene mejor integración congt/flextabley es más extensible. Para proyectos nuevos suele ser la elección por defecto. - Exploración interactiva. Para inspección rápida de un dataset,
skimr::skim()osummarytools::dfSummary()son más ágiles. - Tablas de regresión (coeficientes, OR, HR). Usa
gtsummary::tbl_regression,broom::tidy+gt, omodelsummary.
Conceptos clave
CreateTableOne(vars, strata, data, factorVars, ...)es la función principal.stratadefine las columnas (grupos a comparar).vars, las filas.print()sobre el objeto controla la presentación:nonnormal = c(...)fuerza mediana [IQR] en variables sesgadas.exact = c(...)fuerza test exacto de Fisher en categóricas con celdas pequeñas.smd = TRUEañade la columna de SMD.- Detección automática de tests: chi-cuadrado para categóricas, ANOVA/Kruskal-Wallis para continuas. Si quieres control, especifícalo explícitamente, los defaults pueden no ajustarse a tu protocolo estadístico.
tableone::ShowRegTable()formatea tablas de regresión a partir decoxph,glm, etc.- Exportación:
print(tab, quote = TRUE, noSpaces = TRUE)produce algo pegable directamente en Excel. Para Word/PDF, conviene pasar porkableExtraoflextable.
Patrón mínimo
library(tableone)
vars <- c("age", "sex", "bmi", "smoker", "hba1c", "creatinine")
factor_vars <- c("sex", "smoker")
nonnormal <- c("hba1c", "creatinine") # mostrar como mediana [IQR]
tab <- CreateTableOne(
vars = vars,
strata = "treatment", # grupo a comparar
data = cohort,
factorVars = factor_vars,
test = TRUE
)
# Impresión con ajustes para el manuscrito
print(
tab,
nonnormal = nonnormal,
smd = TRUE,
quote = FALSE,
noSpaces = TRUE
)Trampas habituales
- Variables categóricas no declaradas. Si una variable categórica está codificada como entero (p. ej.
sex = 0/1),tableonela tratará como continua y reportará media ± SD. Declara siemprefactorVarso convierte afactorantes. - Test por defecto vs protocolo. Los defaults aplican chi-cuadrado y ANOVA. Si tu plan estadístico fija Fisher y Kruskal-Wallis, pásalos explícitamente vía
exactynonnormal. No confíes en los defaults para un análisis preregistrado. - SMD con múltiples grupos. Con
stratade más de dos niveles, la SMD se calcula como una versión multivariada (Yang & Dalton). Revisa el output, suele confundirse con la SMD pareada clásica.
Enlaces
Relacionados en esta página
effectsize, para complementar la Tabla 1 con tamaños del efecto y no solo p-values.
effectsize
effectsize es la pieza del ecosistema easystats dedicada a calcular tamaños del efecto y sus intervalos de confianza, de forma coherente, con la misma API independientemente de si parten de un test, un modelo lineal, un GLM o un modelo mixto. Cierra una brecha histórica de R base: los p-values están en todas partes, los tamaños del efecto no.
Su valor real es la coherencia: cohens_d() sobre dos vectores, eta_squared() sobre un lm con varias covariables, standardize_parameters() sobre cualquier modelo de la familia parameters, todo devuelve objetos con CI, interpretación textual opcional y métodos print/plot consistentes.
Cuándo usarlo
- Reportar magnitud del efecto junto al p-value (recomendación estándar de APA, CONSORT y la mayoría de revistas serias hoy).
- Convertir entre métricas de efecto (
d↔︎r↔︎OR) sin tener que recordar fórmulas. - Estandarizar coeficientes de un modelo de regresión sin reescalar manualmente las variables.
- Interpretación cualitativa con
interpret_cohens_d(),interpret_r(), etc., útil cuando escribes un report automático, aunque las reglas (Cohen, Sawilowsky, Funder & Ozer) son convenciones, no leyes.
Cuándo NO usarlo
- Si solo necesitas el coeficiente bruto del modelo,
broom::tidy()es más ligero y suficiente.effectsizeaporta cuando quieres versión estandarizada, eta², omega², o medidas específicas de ANOVA. - Para tamaños del efecto bayesianos (
bayes_R2, posterior ded), usa directamentebrms::bayes_R2()obayestestR,effectsizelos expone, pero la API nativa es más expresiva.
Conceptos clave
- Familia continua-continua:
cohens_d(),hedges_g(),glass_delta()para comparaciones de dos grupos. - Familia ANOVA:
eta_squared(),omega_squared(),epsilon_squared()sobre unaovolm. Por defecto devuelven η² parcial.partial = FALSEpara el clásico. - Familia categórica:
cramers_v(),phi()para tablas de contingencia (a partir dechisq.testotable). - Estandarización de modelos:
standardize_parameters()reescala coeficientes a unidades de desviación típica. Distintos métodos ("refit","posthoc","smart"),"refit"es el más correcto estadísticamente pero el más caro. - Reglas de interpretación.
interpret_*aceptan distintas convenciones (rules = "cohen1988","sawilowsky2009","funder2019"). No las uses como verdad absoluta. Explicita la regla en el manuscrito.
Patrón mínimo
library(effectsize)
# 1) Dos grupos: Cohen's d con CI
cohens_d(mpg ~ am, data = mtcars)
# 2) ANOVA: eta² parcial sobre lm/aov
mod <- lm(mpg ~ cyl + hp + wt, data = mtcars)
eta_squared(mod, partial = TRUE)
# 3) Estandarizar coeficientes de un GLM
glm_mod <- glm(am ~ mpg + wt, data = mtcars, family = binomial())
standardize_parameters(glm_mod, method = "refit")
# 4) Conversión entre métricas
d_to_r(0.5) # Cohen's d a correlación r
oddsratio_to_d(2) # OR a Cohen's d (asume distribución logística)Trampas habituales
- η² parcial vs η² clásico. El default de
eta_squared()espartial = TRUE. En diseños con varias covariables, el η² parcial puede sumar mucho más de 1, eso no es un error, es lo esperado, pero confunde a quien viene de SPSS o de literatura clásica. standardize_parametersno es “estandarizar las variables y refitar”. Por defecto usa una aproximación posthoc (más rápida pero con supuestos). Si quieres el refit correcto, especificamethod = "refit".- Conversiones entre métricas asumen distribuciones.
d_to_r,oddsratio_to_d, etc., aplican fórmulas con supuestos (homocedasticidad, distribución logística…). En datos reales con asimetría fuerte, son aproximaciones, no equivalencias.
Enlaces
Relacionados en esta página
tableone, descriptiva por grupo.effectsizecomplementa con magnitud del efecto.ggstatsplot, internamente usaeffectsizepara anotar los gráficos.
infer
infer es la implementación tidy del flujo de inferencia basado en simulación: permutaciones, bootstrap e intervalos de confianza expresados como una pipeline specify → hypothesize → generate → calculate. Pertenece al proyecto tidymodels y refleja una decisión pedagógica deliberada, separar los pasos conceptuales de la inferencia frecuentista en verbos explícitos.
Su origen es académico (Allen Downey, Andrew Bray, Chester Ismay) y se nota: el paquete está pensado tanto para enseñar como para producir. En producción su valor está en workflows donde necesitas tests no paramétricos sobre estadísticos no convencionales, o donde quieres trazabilidad explícita de qué se está aleatorizando.
Cuándo usarlo
- Tests de permutación y bootstrap con sintaxis legible, especialmente útil cuando el estadístico no tiene distribución cerrada o cuando los supuestos paramétricos son cuestionables.
- Enseñanza de inferencia frecuentista, el código se lee como el razonamiento estadístico.
- Cuando quieres que cada paso (
specify,hypothesize,generate,calculate) sea inspeccionable y reutilizable en un pipeline reproducible.
Cuándo NO usarlo
- Tests clásicos puntuales. Para un
t.test, unchisq.testo una correlación,stats::de base es más directo.inferañade verbosidad sin valor cuando el test es estándar. - Modelado.
inferno ajusta GLMs ni modelos mixtos. Para regresión seria usastats::lm/glm,lme4,glmmTMB,brms, etc., y para tidy de resultados,broom. - Bayesiano. Si el enfoque conceptual del análisis es bayesiano, salta directo a
brms,rstanarmobayestestR.inferes estrictamente frecuentista. - Datasets grandes con muchas permutaciones.
generate(reps = 10000)puede ser caro. En ese régimen, considera tests analíticos o usarcoin(que es más rápido para permutación pura sin pipeline tidy).
Conceptos clave
specify(response ~ explanatory)define el problema. Es declarativo: solo dice qué variables.hypothesize(null = "independence" | "point")fija la hipótesis nula."independence"para tests de asociación."point"para tests sobre un valor concreto (media, proporción).generate(reps, type = "permute" | "bootstrap" | "draw")produce las réplicas simuladas. La elección deltypedebe ser coherente con la nula: permutación para independencia, bootstrap para CIs.calculate(stat)colapsa cada réplica a un estadístico ("mean","diff in means","prop","diff in props","Chisq","F","t","correlation", …).get_p_value(obs_stat, direction)yget_confidence_interval()cierran el flujo. El argumentodirection = "two-sided"/"left"/"right"es explícito,inferno lo adivina.- Modo teórico.
assume(distribution = "t" | "F" | ...)permite recuperar el test paramétrico clásico con la misma sintaxis, útil para comparar simulación vs analítico.
Patrón mínimo
library(infer)
library(dplyr)
# Diferencia de medias por grupo, vía permutación
obs_diff <- gss |>
specify(hours ~ college) |>
calculate(stat = "diff in means", order = c("degree", "no degree"))
null_dist <- gss |>
specify(hours ~ college) |>
hypothesize(null = "independence") |>
generate(reps = 1000, type = "permute") |>
calculate(stat = "diff in means", order = c("degree", "no degree"))
null_dist |> get_p_value(obs_stat = obs_diff, direction = "two-sided")
# Intervalo de confianza bootstrap para la misma diferencia
boot_dist <- gss |>
specify(hours ~ college) |>
generate(reps = 1000, type = "bootstrap") |>
calculate(stat = "diff in means", order = c("degree", "no degree"))
boot_dist |> get_confidence_interval(level = 0.95, type = "percentile")Trampas habituales
order = c("nivel_a", "nivel_b")define el signo de la diferencia (a − b). Omitirlo da una advertencia y un signo arbitrario. Ser explícito ahorra confusión al interpretar.hypothesizevs sinhypothesize. Para CIs por bootstrap no se llama ahypothesize(no hay nula que imponer). Para p-values por permutación, sí. Mezclar los flujos produce resultados sin sentido, el paquete no siempre te avisa.repspequeño. Conreps = 100el p-value es ruidoso. Conreps = 1000ya estabiliza para mayoría de casos. Para tests con p-values muy pequeños, hace faltarepsmucho mayor (la resolución mínima es1/reps).
Enlaces
Relacionados en esta página
effectsize, complemento natural:inferda el p-value/CI,effectsizeda la magnitud.
ggstatsplot
ggstatsplot es un envoltorio de visualización sobre ggplot2 que produce gráficos con los resultados estadísticos anotados directamente, p-values, tamaños del efecto, intervalos de confianza, factores Bayes, sin tener que llamar a los tests por separado y pegarlos a mano con annotate(). Internamente combina effectsize, parameters, BayesFactor y otros paquetes de easystats.
Su autor, Indrajeet Patil, lo concibió como herramienta de comunicación estadística: cuando se reporta una comparación, el lector debería ver simultáneamente la distribución, el efecto, su magnitud y la evidencia contra el nulo. Es una opinión fuerte sobre cómo se debe presentar análisis exploratorio.
Cuándo usarlo
- Exploración rápida de comparaciones donde quieres ver distribución + test + tamaño del efecto en una sola figura.
- Reports internos, slide decks, exploración con stakeholders no estadísticos donde la anotación reduce ambigüedad.
- Comparaciones entre múltiples grupos con tests pairwise corregidos (
pairwise.comparisons = TRUE).
Cuándo NO usarlo
- Figuras de manuscrito final. Las anotaciones por defecto son densas y opinadas, para una figura limpia que respete el estilo de una revista, suele ser preferible construirla a mano con
ggplot2+ggpubr::stat_pvalue_manual()o anotación manual. - Cuando ya tienes el modelo ajustado. Si has corrido un
lm/lmer/glmy quieres visualizar efectos, ve directo aggeffects,marginaleffects, osjPlot.ggstatsplotre-ajusta internamente. - Performance crítico. Cada gráfico dispara múltiples ajustes (frequentista + bayesiano + tamaño del efecto). En datasets grandes o loops, conviene desactivar lo que no uses (
bf.message = FALSE) o usar las funciones de bajo nivel.
Conceptos clave
- API por tipo de plot:
ggbetweenstats(grupos independientes),ggwithinstats(medidas repetidas),ggscatterstats(correlación),ggcorrmat(matriz de correlaciones),ggpiestats/ggbarstats(categóricas),gghistostats(univariado). - Argumento
typecontrola el enfoque:"parametric","nonparametric","robust","bayes". Cambiartypecambia el test, el tamaño del efecto y la métrica de evidencia mostrados. pairwise.comparisons = TRUEañade contrastes pairwise con corrección (p.adjust.method = "holm"por defecto). Útil con >2 grupos, pero satura el gráfico rápidamente.- Bayes Factor automático. El mensaje BF₁₀ aparece por defecto y mide evidencia a favor de la alternativa. Apagarlo (
bf.message = FALSE) limpia la figura. grouped_*variantes generan paneles facetados sobre una variable adicional, conservando los tests por panel.
Patrón mínimo
library(ggstatsplot)
# Comparación entre grupos independientes
ggbetweenstats(
data = iris,
x = Species,
y = Sepal.Length,
type = "parametric", # o "nonparametric", "robust", "bayes"
pairwise.comparisons = TRUE,
p.adjust.method = "holm",
bf.message = FALSE # quita el mensaje de BF si no lo necesitas
)
# Correlación con anotación completa
ggscatterstats(
data = mtcars,
x = wt,
y = mpg,
type = "nonparametric" # Spearman
)Trampas habituales
- Cada
gg*statsre-ajusta el modelo. En un loop con muchas comparaciones, el coste se acumula. Si ya tienes el ajuste, no usesggstatsplot, anota a mano. - Tipografía y leyendas densas. La anotación por defecto incluye estadístico, p-value, tamaño del efecto, IC y BF en una sola línea. En PDF para imprenta queda apretada. Ajusta
ggstatsplot.layer.positiony reducebf.message/results.subtitlesegún necesites. - Defaults frecuentista + bayesiano simultáneo. El gráfico muestra ambos enfoques por defecto. Si tu informe es estrictamente frecuentista o estrictamente bayesiano, configúralo: mezclar paradigmas sin explicar confunde al lector.
Enlaces
Relacionados en esta página
effectsize, motor de cálculo de tamaños del efecto queggstatsplotusa internamente.infer, alternativa cuando quieres el flujo inferencial explícito, no anotación visual automática.