Promedio por grupo en pandas (groupby)

Por el equipo de promedio.net · Actualizado el

Para calcular el promedio por grupo en pandas, agrupa por la columna de categoría y promedia la columna numérica: df.groupby("region")["monto"].mean(). Obtienes una Serie con un promedio por región. Si quieres varias medidas a la vez usa .agg(["mean", "median", "count"]), y si quieres pegar el promedio del grupo a cada fila usa .transform("mean").

Sintaxis

df.groupby("grupo")["valor"].mean()                     # Serie: un promedio por grupo
df.groupby("grupo", as_index=False)["valor"].mean()     # DataFrame con el grupo como columna
df.groupby(["g1", "g2"])["valor"].mean()                # varios niveles
df.groupby("grupo").agg(promedio=("valor", "mean"),
                        ventas=("valor", "size"))       # agregación con nombre
df.groupby("grupo")["valor"].transform("mean")          # mismo largo que df

Paso a paso

  1. Identifica la columna que define los grupos (región, materia, mes) y la que vas a promediar.
  2. Llama a groupby con la primera y selecciona la segunda entre corchetes.
  3. Aplica .mean() para una tabla resumen, o .transform("mean") si necesitas comparar cada fila con su grupo.
  4. Ordena con .sort_values() y redondea con .round(2) para presentar.

Los datos de todos los ejemplos:

import pandas as pd

v = pd.DataFrame({
    "region":   ["Norte", "Sur", "Norte", "Centro", "Sur", "Centro", "Norte"],
    "vendedor": ["Eva", "Raúl", "Iván", "Paz", "Raúl", "Paz", "Eva"],
    "monto":    [1500, 2300, 1800, 900, 2100, 1300, 1100],
})

Ejemplos resueltos

Ejemplo 1: tabla resumen con varias medidas

print(v.groupby("region")["monto"].agg(["mean", "median", "count"]).round(2))
           mean  median  count
region                        
Centro  1100.00  1100.0      2
Norte   1466.67  1500.0      3
Sur     2200.00  2200.0      2

En Norte, el promedio (1,466.67) queda por debajo de la mediana (1,500) porque la venta de 1,100 tira hacia abajo. Mostrar count junto al promedio evita sacar conclusiones de grupos con muy pocas filas. Si prefieres nombres propios para las columnas, usa la agregación con nombre: .agg(promedio=("monto", "mean"), ventas=("monto", "size")).

Ejemplo 2: comparar cada venta con el promedio de su región

v["prom_region"] = v.groupby("region")["monto"].transform("mean").round(2)
v["dif"] = (v["monto"] - v["prom_region"]).round(2)
print(v)
   region vendedor  monto  prom_region     dif
0   Norte      Eva   1500      1466.67   33.33
1     Sur     Raúl   2300      2200.00  100.00
2   Norte     Iván   1800      1466.67  333.33
3  Centro      Paz    900      1100.00 -200.00
4     Sur     Raúl   2100      2200.00 -100.00
5  Centro      Paz   1300      1100.00  200.00
6   Norte      Eva   1100      1466.67 -366.67

transform devuelve un resultado del mismo largo que la tabla original, con el promedio del grupo repetido en cada fila. Con eso puedes filtrar las ventas por encima del promedio de su región: v[v["dif"] > 0].

Ejemplo 3: dos niveles de agrupación

print(v.groupby(["region", "vendedor"])["monto"].mean())
region  vendedor
Centro  Paz         1100.0
Norte   Eva         1300.0
        Iván        1800.0
Sur     Raúl        2200.0
Name: monto, dtype: float64

El resultado tiene un índice de dos niveles. Para verlo como tabla cruzada, con regiones en filas y vendedores en columnas, usa pd.pivot_table(v, values="monto", index="region", columns="vendedor", aggfunc="mean"); las combinaciones sin ventas quedan como NaN.

Filtrar y ordenar grupos

Para quedarte con las regiones cuyo promedio supera 1,300 y ordenarlas de mayor a menor:

prom = v.groupby("region")["monto"].mean()
print(prom[prom > 1300].sort_values(ascending=False).round(2))
region
Sur      2200.00
Norte    1466.67
Name: monto, dtype: float64

Es lo mismo que hace HAVING AVG(monto) > 1300 en SQL, explicado en promedio en SQL.

Errores comunes

Fuentes

  1. pandas, Group by: split-apply-combine. Agregación con nombre, transform. Consultado el 11 de noviembre de 2026.