📈

Funciones Estadísticas

MEDIAN, PERCENTILE, STDEV, RANKX, distribuciones estadísticas y regresión lineal — el análisis estadístico completo en DAX

Intermedio Avanzado
🔍
🎯

Estadística descriptiva vs inferencial en DAX

¿Crees que DAX es solo SUM y COUNT? ¡Para nada! Tiene un conjunto de funciones estadísticas digno de R o Python en modo básico. Desde la mediana hasta distribuciones chi-cuadrado, pasando por regresión lineal. Te cuento cuándo y por qué usarlas en un contexto de BI. 📊

Clasificación rápida de funciones estadísticas

Tipo Qué hace Funciones DAX
Estadística DESCRIPTIVA Describe los datos que tienes MEDIAN, STDEV, VAR, PERCENTILE, RANKX
Estadística INFERENCIAL Hace inferencias sobre una población NORM.DIST, T.DIST, CHISQ.DIST, BETA.DIST
Machine Learning básico Predice valores basándose en patrones LINEST, LINESTX (regresión lineal)
💡 Contexto de uso en Power BI
En la práctica, el 95% del uso estadístico en Power BI es descriptivo — mediana, percentiles, desviación estándar. Las distribuciones estadísticas y la regresión son para usuarios avanzados que integran análisis estadístico directamente en sus informes.
📏

Medidas de posición — dónde están los datos

MEDIAN / MEDIANX
Intermedio
La mediana es el valor central cuando los datos están ordenados. A diferencia de la media (AVERAGE), la mediana NO se ve afectada por valores extremos (outliers). Para distribuciones asimétricas, la mediana es más representativa que la media.

¿Cuándo usar mediana vs media?

// Supongamos salarios: 20.000, 22.000, 24.000, 25.000, 200.000
// (el CEO infla la media)

Salario Medio = AVERAGE('Empleados'[Salario])
// Resultado: 58.200€ (el CEO infla la media)

Salario Mediano = MEDIAN('Empleados'[Salario])
// Resultado: 24.000€ (el valor central real — mucho más representativo)

Ejemplos prácticos

// ✅ Ticket mediano (más robusto que el ticket medio)
Ticket Mediano = MEDIAN('Ventas'[Importe])
Ticket Medio = AVERAGE('Ventas'[Importe])
// Si hay ventas atípicas muy grandes, Ticket Mediano es más representativo

// ✅ MEDIANX — mediana de una expresión calculada
Margen Mediano =
MEDIANX(
    'Pedidos',
    DIVIDE([Margen Pedido], [Importe Pedido])
)
PERCENTILE.INC / PERCENTILE.EXC
Intermedio
Avanzado
Devuelve el percentil k de una columna. k debe ser entre 0 y 1 (0.25 = percentil 25, es decir Q1). INC incluye los extremos (0 y 1 son válidos), EXC los excluye (solo valores estrictamente entre 0 y 1).

Cuartiles y percentiles

// ✅ Cuartiles de ventas
Q1 Ventas = PERCENTILE.INC('Ventas'[Importe], 0.25)  -- 25% inferior
Q2 Ventas = PERCENTILE.INC('Ventas'[Importe], 0.50)  -- mediana
Q3 Ventas = PERCENTILE.INC('Ventas'[Importe], 0.75)  -- 75% inferior
P90 Ventas = PERCENTILE.INC('Ventas'[Importe], 0.90) -- top 10%

// ✅ Rango intercuartílico (IQR — medida de dispersión robusta)
IQR =
    PERCENTILE.INC('Ventas'[Importe], 0.75) -
    PERCENTILE.INC('Ventas'[Importe], 0.25)

// ✅ Detectar outliers (método IQR)
Limite Superior Outlier =
    PERCENTILE.INC('Ventas'[Importe], 0.75) + 1.5 * [IQR]

Limite Inferior Outlier =
    PERCENTILE.INC('Ventas'[Importe], 0.25) - 1.5 * [IQR]

Es Outlier =
OR(
    'Ventas'[Importe] > [Limite Superior Outlier],
    'Ventas'[Importe] < [Limite Inferior Outlier]
)
PERCENTILEX.INC / PERCENTILEX.EXC
Avanzado
Versión iteradora de PERCENTILE — calcula el percentil de una expresión evaluada fila a fila.
// ✅ Percentil 90 del margen calculado por pedido
P90 Margen =
PERCENTILEX.INC(
    'Pedidos',
    DIVIDE(
        SUMX(RELATEDTABLE('Lineas'), 'Lineas'[Margen]),
        SUMX(RELATEDTABLE('Lineas'), 'Lineas'[Importe])
    ),
    0.90
)
📊

Dispersión — cómo de dispersos están los datos

Tabla comparativa de funciones de dispersión

Función Qué mide Variante Cuándo usar
STDEV.P Desv. estándar poblacional Toda la población Tienes TODOS los datos
STDEV.S Desv. estándar muestral Muestra Tienes una MUESTRA de los datos
STDEVX.P Como STDEV.P pero iteradora Expresión por fila Con expresiones calculadas
STDEVX.S Como STDEV.S pero iteradora Expresión por fila Con expresiones calculadas
VAR.P Varianza poblacional Toda la población (STDEV.P al cuadrado)
VAR.S Varianza muestral Muestra (STDEV.S al cuadrado)
VARX.P Varianza poblacional iteradora Expresión por fila Con expresiones calculadas
VARX.S Varianza muestral iteradora Expresión por fila Con expresiones calculadas
STDEV.S
Intermedio
Avanzado
Desviación estándar muestral. Mide cuánto se dispersan los valores respecto a su media. Una desv. estándar alta = datos muy dispersos. Baja = datos concentrados alrededor de la media.

Análisis de consistencia

// ✅ ¿Cómo de consistentes son las ventas diarias?
Consistencia Ventas = STDEV.S('Ventas'[Importe])
// Alta → ventas muy variables día a día (riesgo)
// Baja → ventas estables y predecibles

// ✅ Coeficiente de variación (CV) — dispersión relativa
// Comparable entre medidas con diferentes escalas
CV Ventas = DIVIDE(STDEV.S('Ventas'[Importe]), AVERAGE('Ventas'[Importe]))
// 0.1 = 10% de variación (muy estable)
// 0.5 = 50% de variación (muy variable)
// Permite comparar variabilidad entre métricas con distintas escalas

// ✅ Z-Score — a cuántas desviaciones estándar está cada venta de la media
'Ventas'[Z-Score] =
DIVIDE(
    'Ventas'[Importe] - AVERAGE('Ventas'[Importe]),
    STDEV.S('Ventas'[Importe])
)
// Z > 2 o Z < -2 → posible outlier
// Z = 0 → valor igual a la media
// Z = 1 → una desviación estándar por encima de la media
💡 La regla práctica P vs S
Usa .P (poblacional): Si tus datos son el universo completo (todas las ventas del año pasado).
Usa .S (muestral): Si tus datos son una muestra de una población más grande.

En la práctica de BI, casi siempre usarás .S porque trabajas con los datos disponibles como muestra del comportamiento futuro.
🏅

Rankings — RANKX y RANK.EQ

RANKX
Intermedio
Avanzado
Calcula el ranking de un valor dentro de una tabla. Es un iterador — evalúa la expresión para cada fila de la tabla y determina la posición del valor actual. La función de ranking más usada en Power BI para rankings dinámicos.

Parámetros de RANKX

  • tabla: el conjunto sobre el que ranquear (ALL, VALUES, tabla completa...)
  • expresión: qué se rankea (generalmente una medida)
  • valor: qué valor ranquear (por defecto, la expresión evaluada en el contexto actual)
  • orden: DESC (mayor=1, por defecto) o ASC (menor=1)
  • empates: SKIP (1,2,2,4) o DENSE (1,2,2,3)

Ranking básico de productos

// ✅ Ranking de productos por ventas (el más vendido = posición 1)
Ranking Producto =
RANKX(
    ALL('Productos'),      -- sobre todos los productos
    [Total Ventas],        -- ranquear por ventas totales
    ,                      -- valor actual (se omite = usa la expresión)
    DESC,                  -- mayor ventas = posición 1
    DENSE                  -- sin saltos en empates
)

// ✅ Ranking dentro de categoría
Ranking en Categoría =
RANKX(
    ALLEXCEPT('Productos', 'Productos'[Categoría]),
    -- solo productos de la misma categoría
    [Total Ventas],
    ,
    DESC,
    DENSE
)

// ✅ Usar RANKX para mostrar solo el Top N
Es Top 10 = IF([Ranking Producto] <= 10, TRUE, FALSE)

// ✅ Top N dinámico (con slicer de N)
Top N Ventas =
VAR N = SELECTEDVALUE('TopN Selector'[Valor], 10)
RETURN
    IF([Ranking Producto] <= N, [Total Ventas], BLANK())
⚠️ Performance con RANKX
RANKX puede ser lento en tablas grandes porque es un iterador que evalúa la expresión para CADA FILA de la tabla especificada. Si la tabla tiene millones de filas, considera usar la función RANK (Window Function) en tablas calculadas, o limitar la tabla con TOPN primero.
RANK.EQ
Avanzado
Versión simplificada de ranking — busca la posición de un valor específico dentro de una columna. No es iteradora. Menos flexible que RANKX pero más directa para casos simples.
// ✅ Posición de una categoría específica en la lista de ventas
Posición Electrónica =
RANK.EQ(
    [Ventas Electrónica],
    'ResumenCategorías'[TotalVentas],
    DESC
)
🎲

Muestras y medias geométricas

SAMPLE
Avanzado
Devuelve una muestra de N filas de una tabla, ordenadas por la expresión especificada. Útil para mostrar ejemplos representativos o hacer muestreo sistemático.
// ✅ Mostrar 10 transacciones representativas (distribuidas uniformemente)
Muestra Transacciones =
SAMPLE(10, 'Ventas', 'Ventas'[Importe], ASC)
// Devuelve 10 filas de Ventas distribuidas a lo largo del rango de importes
GEOMEAN / GEOMEANX
Avanzado
Media geométrica — la raíz N-ésima del producto de N valores. Perfecta para promediar tasas de crecimiento, rendimientos compuestos y ratios multiplicativos.

¿Cuándo usar media geométrica vs aritmética?

// Si tienes rendimientos: +50%, -50%
// Media aritmética: (50 + (-50)) / 2 = 0% → parece neutro
// Pero si inviertes 100€:
// +50% → 150€, luego -50% → 75€ (¡has perdido dinero!)
// Media geométrica: SQRT(1.5 × 0.5) - 1 = -13.4% → refleja la realidad

CAGR (tasa de crecimiento compuesto anual)

// ✅ CAGR = (Valor Final / Valor Inicial)^(1/años) - 1
CAGR =
VAR ValorInicial = FIRSTNONBLANK('Ventas'[TotalAño], 1)
VAR ValorFinal = LASTNONBLANK('Ventas'[TotalAño], 1)
VAR Años = DATEDIFF(MIN('Calendario'[Fecha]), MAX('Calendario'[Fecha]), YEAR)
RETURN
    POWER(DIVIDE(ValorFinal, ValorInicial), DIVIDE(1, Años)) - 1

// ✅ Alternativa con GEOMEANX (para factores de crecimiento año a año)
CAGR con Geomean =
GEOMEANX('Crecimientos', 1 + 'Crecimientos'[Tasa]) - 1
📉

LINEST y LINESTX — regresión lineal en DAX

Sí, DAX puede hacer regresión lineal. Quizás no al nivel de Python con scikit-learn, pero sí lo suficiente para calcular tendencias, coeficientes de correlación y líneas de ajuste directamente en Power BI.

LINEST
Avanzado
Calcula los coeficientes de la regresión lineal simple (y = mx + b) entre dos columnas. Devuelve una tabla de dos columnas: el slope (pendiente m) y el intercept (ordenada al origen b).

Línea de tendencia de ventas

// ✅ Calcular la pendiente de la tendencia de ventas en el tiempo
Ventas Predichas =
VAR RegresionTabla =
    LINEST(
        SUMMARIZE('Ventas', 'Calendario'[MesNum], "Y", SUM('Ventas'[Importe])),
        [Y],         -- variable dependiente: ventas
        [MesNum]     -- variable independiente: número de mes
    )
VAR Slope = MAXX(FILTER(RegresionTabla, [Nombre] = "Slope"), [Valor])
VAR Intercept = MAXX(FILTER(RegresionTabla, [Nombre] = "Intercept"), [Valor])
RETURN
    -- Ventas predichas para el mes N:
    Slope * [MesNum] + Intercept
LINESTX
Avanzado
Versión iteradora de LINEST. Más flexible porque las variables Y y X son expresiones evaluadas fila a fila, no columnas directas.

Correlación entre descuento y margen

// ✅ ¿A mayor descuento, menor margen? (esperamos que sí...)
Pendiente Descuento-Margen =
VAR Regresion =
    LINESTX(
        'Ventas',
        'Ventas'[Margen],    -- Y: lo que queremos predecir
        'Ventas'[Descuento]  -- X: el predictor
    )
VAR Pendiente = MAXX(FILTER(Regresion, [Nombre] = "Slope"), [Valor])
RETURN Pendiente
// Pendiente negativa → a mayor descuento, menor margen (confirma la hipótesis)
// Pendiente positiva → algo raro pasa (revisar datos)
💡 Análisis estadístico más profundo
Para análisis estadístico más profundo (regresión múltiple, Machine Learning, clustering) considera usar Python o R integrado en Power BI, o exportar los datos a Fabric para procesarlos con notebooks. LINEST es útil para tendencias simples directamente en el modelo.
🔔

Distribuciones estadísticas — para análisis avanzado

Estas funciones son el territorio de las personas con formación en estadística. Si eres analista de datos, ingeniera o científica de datos, las reconocerás inmediatamente. Si no tienes ese background, no te preocupes — la mayoría de proyectos de BI no las necesitan. Pero están aquí para cuando las necesites.

Tabla de todas las distribuciones disponibles

Distribución Funciones DAX Uso principal
Normal NORM.DIST, NORM.INV, NORM.S.DIST, NORM.S.INV Intervalos de confianza, z-scores
T de Student T.DIST, T.DIST.2T, T.DIST.RT, T.INV, T.INV.2T Tests de hipótesis con muestras pequeñas
Chi-cuadrado CHISQ.DIST, CHISQ.DIST.RT, CHISQ.INV, CHISQ.INV.RT Tests de independencia, goodness of fit
Beta BETA.DIST, BETA.INV Probabilidades de proporciones (ej: tasa de conversión)
Exponencial EXPON.DIST Tiempos entre eventos (procesos de Poisson)
Poisson POISSON.DIST Conteo de eventos en un intervalo
NORM.DIST
Avanzado
Distribución normal. Si acumulado=TRUE devuelve P(X ≤ x); si FALSE devuelve la función de densidad. Fundamental para calcular probabilidades e intervalos de confianza.

Probabilidad de superar un umbral

// ✅ ¿Cuál es la probabilidad de que las ventas de mañana sean > 5000€?
// Asumiendo que las ventas siguen una distribución normal con media=4000 y σ=800
P(Ventas > 5000) = 1 - NORM.DIST(5000, 4000, 800, TRUE)
// Resultado: ~10.6%

// ✅ Intervalo de confianza del 95% para la media de ventas
IC 95% Ventas =
VAR Media = AVERAGE('Ventas'[Importe])
VAR Sigma = STDEV.S('Ventas'[Importe])
VAR N = COUNTROWS('Ventas')
VAR MargenError = 1.96 * DIVIDE(Sigma, SQRT(N))  -- 1.96 = z para 95%
VAR LimiteSup = Media + MargenError
VAR LimiteInf = Media - MargenError
RETURN
    "IC 95%: [" & FORMAT(LimiteInf, "#,##0") & ", " & FORMAT(LimiteSup, "#,##0") & "]"
BETA.DIST
Avanzado
Distribución Beta. Perfecta para modelar probabilidades (valores entre 0 y 1) como tasas de conversión, porcentajes de éxito. Muy usada en análisis Bayesiano de A/B tests.

A/B Test bayesiano simple

// Versión A: 100 visitas, 10 conversiones (alpha=11, beta=91)
// Versión B: 100 visitas, 15 conversiones (alpha=16, beta=86)
// ¿Cuál es mejor con qué probabilidad?

// ✅ Probabilidad de que la tasa de conversión de B > 5%
P(B > 0.05) = 1 - BETA.DIST(0.05, 16, 86, TRUE)
🎲

Combinatoria estadística

Aunque las funciones combinatorias (COMBIN, COMBINA, PERMUT) están documentadas en la página de Funciones Matemáticas, aquí te dejamos un recordatorio rápido porque son fundamentales para cálculos de probabilidad.

Función Qué calcula Ejemplo
COMBIN(n, k) Combinaciones sin repetición ¿De cuántas formas puedo elegir 3 productos de 10? → COMBIN(10, 3) = 120
COMBINA(n, k) Combinaciones con repetición ¿De cuántas formas puedo elegir 3 productos de 10 (con repetición)? → COMBINA(10, 3) = 220
PERMUT(n, k) Permutaciones (orden importa) ¿De cuántas formas puedo ordenar 3 productos de 10? → PERMUT(10, 3) = 720
🎯

Patrones de análisis estadístico

🏆 Patrón 1: Dashboard de estadísticas descriptivas
// Tabla calculada con resumen estadístico de ventas
Resumen Estadístico =
DATATABLE(
    "Estadístico", STRING,
    "Valor", DOUBLE,
    {
        {"Media", AVERAGE('Ventas'[Importe])},
        {"Mediana", MEDIAN('Ventas'[Importe])},
        {"Desv. Estándar", STDEV.S('Ventas'[Importe])},
        {"Mínimo", MIN('Ventas'[Importe])},
        {"Q1 (25%)", PERCENTILE.INC('Ventas'[Importe], 0.25)},
        {"Q3 (75%)", PERCENTILE.INC('Ventas'[Importe], 0.75)},
        {"Máximo", MAX('Ventas'[Importe])}
    }
)
🏆 Patrón 2: Detección automática de outliers
Es Outlier =
VAR Q1 = PERCENTILE.INC(ALL('Ventas'[Importe]), 0.25)
VAR Q3 = PERCENTILE.INC(ALL('Ventas'[Importe]), 0.75)
VAR IQR = Q3 - Q1
RETURN
    OR(
        'Ventas'[Importe] < Q1 - 1.5 * IQR,
        'Ventas'[Importe] > Q3 + 1.5 * IQR
    )
🚀 Siguiente paso
¡Impresionante — ya manejas estadística en DAX! Ahora pasamos a algo más visual y muy usado en el día a día: las funciones de texto para formatear, limpiar y transformar cadenas de caracteres. 🚀