VARIANCE
La función VARIANCE calcula la varianza poblacional de un conjunto de valores numéricos. La varianza es una medida de dispersión que indica cuánto se alejan los valores individuales de la media del grupo. Matemáticamente, es el cuadrado de la desviación estándar: si STD devuelve 10, VARIANCE devuelve 100. Aunque la desviación estándar es más intuitiva (se expresa en las mismas unidades que los datos), la varianza tiene propiedades matemáticas que la hacen útil en análisis más avanzados, como la descomposición de la variabilidad total en componentes.
MySQL ofrece dos sinónimos: VARIANCE y VAR_POP. Ambos calculan exactamente lo mismo: la varianza poblacional, que divide la suma de los cuadrados de las diferencias por N (el número total de valores).
Sintaxis
VARIANCE(expresion)
VAR_POP(expresion)La fórmula que aplica MySQL es:
VARIANCE = SUM((x - media)^2) / N
Donde x es cada valor, media es el promedio y N es el número de valores no nulos. Observa que esta fórmula es equivalente a elevar al cuadrado el resultado de STD.
Comportamiento básico
Veamos la varianza de los precios de todos los productos y su relación con la desviación estándar:
SELECT
ROUND(AVG(precio), 2) AS precio_medio,
ROUND(VARIANCE(precio), 2) AS varianza,
ROUND(STD(precio), 2) AS desviacion_estandar,
ROUND(SQRT(VARIANCE(precio)), 2) AS raiz_varianza
FROM productos;| precio_medio | varianza | desviacion_estandar | raiz_varianza |
|---|---|---|---|
| 384.52 | 183757.41 | 428.67 | 428.67 |
La raíz cuadrada de la varianza (183757.41) es exactamente la desviación estándar (428.67). Esto confirma la relación directa entre ambas funciones. La varianza tiene un valor mucho más grande porque está expresada en unidades al cuadrado (euros al cuadrado, en este caso), lo que la hace menos intuitiva para interpretar directamente.
Caso práctico: comparar homogeneidad entre categorías
La varianza permite comparar cuán homogéneos son los precios dentro de cada categoría:
SELECT
c.nombre AS categoria,
COUNT(*) AS productos,
ROUND(AVG(p.precio), 2) AS precio_medio,
ROUND(VARIANCE(p.precio), 2) AS varianza,
ROUND(STD(p.precio), 2) AS desviacion
FROM productos p
JOIN categorias c ON p.categoria_id = c.id
GROUP BY c.nombre
ORDER BY varianza DESC;| categoria | productos | precio_medio | varianza | desviacion |
|---|---|---|---|---|
| Portátiles | 8 | 1245.50 | 119163.04 | 345.20 |
| Smartphones | 12 | 785.42 | 97531.29 | 312.30 |
| Deportes | 4 | 189.99 | 21083.04 | 145.20 |
| Hogar | 5 | 124.80 | 9702.25 | 98.50 |
| Ropa mujer | 6 | 64.99 | 1482.25 | 38.50 |
| Ropa hombre | 6 | 59.99 | 1075.84 | 32.80 |
| Accesorios electrónicos | 7 | 42.85 | 835.21 | 28.90 |
| Libros | 2 | 22.50 | 56.25 | 7.50 |
Los portátiles tienen la mayor varianza (119163.04), lo que indica la mayor dispersión de precios. Los libros tienen la menor varianza (56.25), con precios muy cercanos entre sí. Cuando comparas categorías con escalas de precios muy diferentes, el coeficiente de variación (desviación entre media) es más apropiado que la varianza en bruto.
Caso práctico: análisis de consistencia en ventas
La varianza de los totales de pedido puede revelar cuán predecibles son las ventas:
SELECT
DATE_FORMAT(fecha_pedido, '%Y-%m') AS mes,
COUNT(*) AS num_pedidos,
ROUND(AVG(total), 2) AS ticket_medio,
ROUND(VARIANCE(total), 2) AS varianza_ticket,
ROUND(STD(total), 2) AS desviacion_ticket
FROM pedidos
WHERE estado = 'completado'
AND YEAR(fecha_pedido) = 2025
GROUP BY DATE_FORMAT(fecha_pedido, '%Y-%m')
ORDER BY mes;| mes | num_pedidos | ticket_medio | varianza_ticket | desviacion_ticket |
|---|---|---|---|---|
| 2025-01 | 20 | 922.54 | 148379.04 | 385.20 |
| 2025-02 | 23 | 927.00 | 170156.25 | 412.50 |
| 2025-03 | 27 | 958.90 | 127306.24 | 356.80 |
| 2025-04 | 21 | 946.22 | 158722.56 | 398.40 |
| 2025-05 | 25 | 966.03 | 143565.21 | 378.90 |
| 2025-06 | 30 | 985.35 | 119439.36 | 345.60 |
Junio tiene el ticket medio más alto y la varianza más baja, lo que indica ventas consistentes con valores similares. Febrero, por el contrario, tiene alta varianza, lo que sugiere una mezcla de pedidos pequeños y grandes.
Caso práctico: descomposición de varianza entre grupos
Un uso avanzado de la varianza es descomponer la variabilidad total en dos componentes: la varianza entre grupos (diferencias entre las medias de cada categoría) y la varianza dentro de los grupos (diferencias dentro de cada categoría):
SELECT
ROUND(VARIANCE(precio), 2) AS varianza_total,
ROUND(VARIANCE(avg_cat), 2) AS varianza_entre_grupos,
ROUND(AVG(var_dentro), 2) AS varianza_dentro_grupos
FROM productos p
JOIN (
SELECT
categoria_id,
AVG(precio) AS avg_cat,
VARIANCE(precio) AS var_dentro
FROM productos
GROUP BY categoria_id
) stats ON p.categoria_id = stats.categoria_id;| varianza_total | varianza_entre_grupos | varianza_dentro_grupos |
|---|---|---|
| 183757.41 | 148230.50 | 35526.91 |
La mayor parte de la varianza total (148230.50 de 183757.41) se debe a las diferencias entre categorías, no a las diferencias dentro de cada categoría. Esto confirma que el precio depende mucho más de la categoría del producto que de otros factores.
Manejo de NULL
VARIANCE ignora los valores NULL. Si todas las filas contienen NULL, devuelve NULL. Si solo hay un valor no nulo, la varianza es 0:
SELECT
VARIANCE(descuento) AS varianza_descuento,
COUNT(descuento) AS productos_con_descuento
FROM productos;| varianza_descuento | productos_con_descuento |
|---|---|
| 42.35 | 12 |
La varianza de 42.35 se calcula solo sobre los 12 productos que tienen descuento. Los 38 productos con descuento como NULL se excluyen completamente del cálculo.
Si quieres incluir los NULL como cero:
SELECT
ROUND(VARIANCE(descuento), 2) AS var_sin_null,
ROUND(VARIANCE(IFNULL(descuento, 0)), 2) AS var_con_ceros
FROM productos;| var_sin_null | var_con_ceros |
|---|---|
| 42.35 | 18.90 |
Al incluir los ceros, la varianza cambia porque el promedio baja (hay más valores cerca de cero) y la distribución se modifica.
Combinación con otras funciones
VARIANCE se combina con HAVING para filtrar grupos según su dispersión:
SELECT
c.nombre AS categoria,
ROUND(AVG(p.precio), 2) AS precio_medio,
ROUND(VARIANCE(p.precio), 2) AS varianza
FROM productos p
JOIN categorias c ON p.categoria_id = c.id
GROUP BY c.nombre
HAVING VARIANCE(p.precio) > 10000
ORDER BY varianza DESC;| categoria | precio_medio | varianza |
|---|---|---|
| Portátiles | 1245.50 | 119163.04 |
| Smartphones | 785.42 | 97531.29 |
| Deportes | 189.99 | 21083.04 |
Esta consulta encuentra las categorías con mayor dispersión de precios, que podrían beneficiarse de una segmentación en subcategorías (como "Smartphones gama alta" y "Smartphones gama media").
También puedes verificar la relación entre VARIANCE y STD:
SELECT
ROUND(VARIANCE(precio), 4) AS varianza,
ROUND(STD(precio) * STD(precio), 4) AS std_al_cuadrado,
ROUND(VARIANCE(precio) - STD(precio) * STD(precio), 10) AS diferencia
FROM productos;La diferencia será 0 (o prácticamente 0, salvo por errores de redondeo de punto flotante), confirmando que VARIANCE = STD^2.
En el siguiente artículo veremos VAR_SAMP para la varianza muestral.
Escrito por Eduardo Lázaro
