Usando datos de muestra:
df = pd.DataFrame({'key1' : ['a','a','b','b','a'], 'key2' : ['one', 'two', 'one', 'two', 'one'], 'data1' : np.random.randn(5), 'data2' : np. random.randn(5)})
df
data1 data2 key1 key2 0 0.361601 0.375297 a one 1 0.069889 0.809772 a two 2 1.468194 0.272929 b one 3 -1.138458 0.865060 b two 4 -0.268210 1.250340 a one
Estoy tratando de averiguar cómo agrupar los datos por clave1 y sumr solo los valores de datos1 donde clave2 es igual a ‘uno’.
Esto es lo que he intentado
def f(d,a,b): d.ix[d[a] == b, 'data1'].sum() df.groupby(['key1']).apply(f, a = 'key2', b = 'one').reset_index()
Pero esto me da un dataframe con valores ‘Ninguno’
index key1 0 0 a None 1 b None
¿Alguna idea aquí? Estoy buscando el equivalente de Pandas del siguiente SQL:
SELECT Key1, SUM(CASE WHEN Key2 = 'one' then data1 else 0 end) FROM df GROUP BY key1
FYI – He visto sums condicionales para pandas agregadas, pero no pude transformar la respuesta proporcionada allí para trabajar con sums en lugar de conteos.
Gracias por adelantado
Primer grupo por la columna key1:
In [11]: g = df.groupby('key1')
y luego, para cada grupo, tome el subDataFrame donde key2 es igual a ‘one’ y sume la columna data1:
In [12]: g.apply(lambda x: x[x['key2'] == 'one']['data1'].sum()) Out[12]: key1 a 0.093391 b 1.468194 dtype: float64
Para explicar lo que está pasando, veamos el grupo ‘a’:
In [21]: a = g.get_group('a') In [22]: a Out[22]: data1 data2 key1 key2 0 0.361601 0.375297 a one 1 0.069889 0.809772 a two 4 -0.268210 1.250340 a one In [23]: a[a['key2'] == 'one'] Out[23]: data1 data2 key1 key2 0 0.361601 0.375297 a one 4 -0.268210 1.250340 a one In [24]: a[a['key2'] == 'one']['data1'] Out[24]: 0 0.361601 4 -0.268210 Name: data1, dtype: float64 In [25]: a[a['key2'] == 'one']['data1'].sum() Out[25]: 0.093391000000000002
Puede ser un poco más fácil / claro hacer esto restringiendo el dataframe a solo aquellos con clave2 que es igual a uno primero:
In [31]: df1 = df[df['key2'] == 'one'] In [32]: df1 Out[32]: data1 data2 key1 key2 0 0.361601 0.375297 a one 2 1.468194 0.272929 b one 4 -0.268210 1.250340 a one In [33]: df1.groupby('key1')['data1'].sum() Out[33]: key1 a 0.093391 b 1.468194 Name: data1, dtype: float64
Creo que hoy con pandas 0.23 puedes hacer esto:
import numpy as np df.assign(result = np.where(df['key2']=='one',df.data1,0))\ .groupby('key1').agg({'result':sum})
La ventaja de esto es que puede aplicarlo a más de una columna del mismo dataframe
df.assign( result1 = np.where(df['key2']=='one',df.data1,0), result2 = np.where(df['key2']=='two',df.data1,0) ).groupby('key1').agg({'result1':sum, 'result2':sum})
Puede filtrar su dataframe antes de realizar su operación groupby
. Si esto reduce su índice de la serie debido a que todos los valores están fuera de scope, puede usar fillna
con fillna
:
res = df.loc[df['key2'].eq('one')]\ .groupby('key1')['data1'].sum()\ .reindex(df['key1'].unique()).fillna(0) print(res) key1 a 3.631610 b 0.978738 c 0.000000 Name: data1, dtype: float64
He añadido una fila adicional para fines de demostración.
np.random.seed(0) df = pd.DataFrame({'key1': ['a','a','b','b','a','c'], 'key2': ['one', 'two', 'one', 'two', 'one', 'two'], 'data1': np.random.randn(6), 'data2': np.random.randn(6)})