Filtrar filas tras grupo por pandas

Tengo una mesa en pandas:

import pandas as pd df = pd.DataFrame({ 'LeafID':[1,1,2,1,3,3,1,6,3,5,1], 'pidx':[10,10,300,10,30,40,20,10,30,45,20], 'pidy':[20,20,400,20,15,20,12,43,54,112,23], 'count':[10,20,30,40,80,10,20,50,30,10,70], 'score':[10,10,10,22,22,3,4,5,9,0,1] }) LeafID count pidx pidy score 0 1 10 10 20 10 1 1 20 10 20 10 2 2 30 300 400 10 3 1 40 10 20 22 4 3 80 30 15 22 5 3 10 40 20 3 6 1 20 20 12 4 7 6 50 10 43 5 8 3 30 20 54 9 9 5 10 45 112 0 10 1 70 20 23 1 

Quiero hacer un groupby y luego filtrar las filas donde la ocurrencia de pidx es mayor que 2.

Es decir, filtrar filas donde pidx es 10 y 20.

Intenté usar df.groupby('pidx').count() pero no me ayudó. También para esas filas tengo que hacer 0.4 * count + 0.6 * score.

La salida deseada es:

 LeafID count pidx pidy final_score 1 10 10 20 1 20 10 20 1 40 10 20 6 50 10 43 1 20 20 12 3 30 20 54 1 70 20 23 

Puedes usar value_counts con boolean indexing e isin :

 df = pd.DataFrame({ 'LeafID':[1,1,2,1,3,3,1,6,3,5,1], 'pidx':[10,10,300,10,30,40,20,10,30,45,20], 'pidy':[20,20,400,20,15,20,12,43,54,112,23], 'count':[10,20,30,40,80,10,20,50,30,10,70], 'score':[10,10,10,22,22,3,4,5,9,0,1] }) print (df) LeafID count pidx pidy score 0 1 10 10 20 10 1 1 20 10 20 10 2 2 30 300 400 10 3 1 40 10 20 22 4 3 80 30 15 22 5 3 10 40 20 3 6 1 20 20 12 4 7 6 50 10 43 5 8 3 30 30 54 9 9 5 10 45 112 0 10 1 70 20 23 1 s = df.pidx.value_counts() idx = s[s>2].index print (df[df.pidx.isin(idx)]) LeafID count pidx pidy score 0 1 10 10 20 10 1 1 20 10 20 10 3 1 40 10 20 22 7 6 50 10 43 5 

Tiempos :

 np.random.seed(123) N = 1000000 L1 = list('abcdefghijklmnopqrstu') L2 = list('efghijklmnopqrstuvwxyz') df = pd.DataFrame({'LeafId':np.random.randint(1000, size=N), 'pidx': np.random.randint(10000, size=N), 'pidy': np.random.choice(L2, N), 'count':np.random.randint(1000, size=N)}) print (df) print (df.groupby('pidx').filter(lambda x: len(x) > 120)) def jez(df): s = df.pidx.value_counts() return df[df.pidx.isin(s[s>120].index)] print (jez(df)) In [55]: %timeit (df.groupby('pidx').filter(lambda x: len(x) > 120)) 1 loop, best of 3: 1.17 s per loop In [56]: %timeit (jez(df)) 10 loops, best of 3: 141 ms per loop In [62]: %timeit (df[df.groupby('pidx').pidx.transform('size') > 120]) 10 loops, best of 3: 102 ms per loop In [63]: %timeit (df[df.groupby('pidx').pidx.transform(len) > 120]) 1 loop, best of 3: 685 ms per loop In [64]: %timeit (df[df.groupby('pidx').pidx.transform('count') > 120]) 10 loops, best of 3: 104 ms per loop 

Para final_score puedes usar:

 df['final_score'] = df['count'].mul(.4).add(df.score.mul(.6)) 

Esta es una aplicación sencilla de filtro después de hacer un groupby. En los datos que proporcionó, un valor de 20 para pidx solo ocurrió dos veces, por lo que se eliminó.

 df.groupby('pidx').filter(lambda x: len(x) > 2) LeafID count pidx pidy 0 1 10 10 20 1 1 20 10 20 3 1 40 10 20 7 6 50 10 43 

pandas

 df[df.groupby('pidx').pidx.transform('count') > 2] LeafID count pidx pidy score 0 1 10 10 20 10 1 1 20 10 20 10 3 1 40 10 20 22 7 6 50 10 43 5 

En primer lugar, su salida muestra que no desea hacer un groupby. Lee sobre lo que Groupby hace. Lo que necesitas es:

 df2 = df[df['pidx']<=20] df2.sort_index(by = 'pidx') 

Esto le dará su resultado exacto. Lee sobre indexación y funciones de pandas. De hecho ve y lee toda la introducción sobre pandas. No tomará mucho tiempo.

Las operaciones de fila también son simples usando indexación:

 df2['final_score']= 0.4*df2['count'] + 0.6*df2['score']