Python Pandas Conditional Sum con Groupby

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 

Preparar

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)})