Intentando crear una nueva columna a partir del groupby
cálculo. En el siguiente código, obtengo los valores calculados correctos para cada fecha (vea el grupo a continuación) pero cuando intento crear una nueva columna ( df['Data4']
) con ella, obtengo NaN. Así que estoy tratando de crear una nueva columna en el marco de datos con la suma de Data3
todas las fechas y aplicarla a cada fila de fechas. Por ejemplo, 2015-05-08 está en 2 filas (el total es 50 + 5 = 55) y en esta nueva columna me gustaría tener 55 en ambas filas.
import pandas as pd
import numpy as np
from pandas import DataFrame
df = pd.DataFrame({
'Date' : ['2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05', '2015-05-08', '2015-05-07', '2015-05-06', '2015-05-05'],
'Sym' : ['aapl', 'aapl', 'aapl', 'aapl', 'aaww', 'aaww', 'aaww', 'aaww'],
'Data2': [11, 8, 10, 15, 110, 60, 100, 40],
'Data3': [5, 8, 6, 1, 50, 100, 60, 120]
})
group = df['Data3'].groupby(df['Date']).sum()
df['Data4'] = group
python
pandas
group-by
pandas-groupby
fe ner
fuente
fuente
df.groupby('Date')['Data3'].transform('sum')
(que encuentro un poco más fácil de recordar).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 deSeries.groupby
. Esto da como resultado una sintaxis más simple.# The setup. 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 directaGroupBy
y la transmites usandomap
: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 directaGroupBy
función (comomean
,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 )
fuente