¿Cómo creo una nueva columna con Groupby (). Sum ()?
Hay dos formas: una sencilla y la otra un poco más interesante.
El favorito de todos: GroupBy.transform()
con'sum'
La respuesta de @Ed Chum se puede simplificar un poco. Llame en DataFrame.groupby
lugar de Series.groupby
. Esto da como resultado una sintaxis más simple.
df[['Date', 'Data3']]
Date Data3
0 2015-05-08 5
1 2015-05-07 8
2 2015-05-06 6
3 2015-05-05 1
4 2015-05-08 50
5 2015-05-07 100
6 2015-05-06 60
7 2015-05-05 120
df.groupby('Date')['Data3'].transform('sum')
0 55
1 108
2 66
3 121
4 55
5 108
6 66
7 121
Name: Data3, dtype: int64
Es un poco más rápido
df2 = pd.concat([df] * 12345)
%timeit df2['Data3'].groupby(df['Date']).transform('sum')
%timeit df2.groupby('Date')['Data3'].transform('sum')
10.4 ms ± 367 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
8.58 ms ± 559 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Poco convencional, pero vale la pena considerarlo: GroupBy.sum()
+Series.map()
Me encontré con una idiosincrasia interesante en la API. Por lo que digo, puede reproducir esto en cualquier versión principal superior a 0.20 (probé esto en 0.23 y 0.24). Parece que puedes reducir constantemente algunos milisegundos del tiempo que tardas transform
si, en cambio, usas una función directa GroupBy
y la transmites usando map
:
df.Date.map(df.groupby('Date')['Data3'].sum())
0 55
1 108
2 66
3 121
4 55
5 108
6 66
7 121
Name: Date, dtype: int64
Comparar con
df.groupby('Date')['Data3'].transform('sum')
0 55
1 108
2 66
3 121
4 55
5 108
6 66
7 121
Name: Data3, dtype: int64
Mis pruebas muestran que map
es un poco más rápido si usted puede permitirse el lujo de usar la directa GroupBy
función (como mean
, min
, max
, first
, etc). Es más o menos más rápido para la mayoría de situaciones generales hasta alrededor de ~ 200 mil registros. Después de eso, el rendimiento realmente depende de los datos.
(Izquierda: v0.23, Derecha: v0.24)
Buena alternativa para conocer, y mejor si tiene marcos más pequeños con un menor número de grupos. . . pero lo recomendaría transform
como primera opción. Pensé que valía la pena compartir esto de todos modos.
Código de evaluación comparativa, como referencia:
import perfplot
perfplot.show(
setup=lambda n: pd.DataFrame({'A': np.random.choice(n//10, n), 'B': np.ones(n)}),
kernels=[
lambda df: df.groupby('A')['B'].transform('sum'),
lambda df: df.A.map(df.groupby('A')['B'].sum()),
],
labels=['GroupBy.transform', 'GroupBy.sum + map'],
n_range=[2**k for k in range(5, 20)],
xlabel='N',
logy=True,
logx=True
)