2012-04-04 15 views
6

¿Es posible calcular directamente el producto (o, por ejemplo, suma) de dos columnas sin usarfunciones GroupBy en pandas Python como SUM (col_1 * col_2), promedio ponderado etc

grouped.apply(lambda x: (x.a*x.b).sum() 

Es mucho (menos de la mitad del tiempo en mi máquina) más rápido usar

df['helper'] = df.a*df.b 
grouped= df.groupby(something) 
grouped['helper'].sum() 
df.drop('helper', axis=1) 

pero no me gusta mucho tener que hacer esto. Por ejemplo, es útil calcular el promedio ponderado por grupo. Aquí el enfoque lambda sería

grouped.apply(lambda x: (x.a*x.b).sum()/(df.b).sum()) 

y de nuevo es mucho más lento que dividir el asistente por b.sum().

Respuesta

7

Quiero construir finalmente un evaluador de expresiones matriz incorporado (Numexpr en los esteroides) para hacer cosas como esta. En este momento estamos trabajando con las limitaciones de Python-- si implementado un agregador Cython hacer (x * y).sum() entonces podría estar conectado con GroupBy, pero lo ideal es que podríamos escribir la expresión como una función de Python:

def weight_sum(x, y): 
    return (x * y).sum() 

y que obtendría "JIT-compiled" y sería tan rápido como groupby (...). sum(). Lo que estoy describiendo es un proyecto bastante significativo (muchos meses). Si hubiera una implementación de APL compatible con BSD, podría hacer algo como lo anterior más arriba (solo pensar en voz alta).

0

¿Qué tal grupo directamente el resultado de x.a * x.b, por ejemplo:

from pandas import * 
from numpy.random import randn 
df = DataFrame({'A' : ['foo', 'bar', 'foo', 'bar', 
       'foo', 'bar', 'foo', 'foo'], 
     'B' : ['one', 'one', 'two', 'three', 
       'two', 'two', 'one', 'three'], 
     'C' : randn(8), 'D' : randn(8)}) 

print (df.C*df.D).groupby(df.A).sum() 
+0

Esto funciona, por supuesto. Pero sospecho que primero todo el vector C * D está construido en la memoria, luego se agrupa y luego se suma. No tendría que hacer esto si pudiera caminar de manera eficiente por las filas, sumando c_i * d_i (o solo construyendo C * D en grupos y luego sumarlos mientras caminaba por los grupos). –

0

La respuesta llegó muchos años después a través de pydata blaze

from blaze import * 
data = Data(df) 
somethings = odo(
by(data.something, 
    wm = (data.a * data.weights).sum()/data.weights.sum()), 
pd.DataFrame) 
Cuestiones relacionadas