contar filas por cierta combinación de valores de fila pandas

Tengo un dataframe (df) como este:

v1 v2 v3 0 -30 -15 0 -30 -7.5 0 -30 -11.25 0 -30 -13.125 0 -30 -14.0625 0 -30 -13.59375 0 -10 -5 0 -10 -7.5 0 -10 -6.25 0 -10 -5.625 0 -10 -5.9375 0 -10 -6.09375 0 -5 -2.5 0 -5 -1.25 0 -5 -1.875 

Las filas están en el mismo fragmento si con cierto / same v1 y v2 . En este caso, las filas con ([0,-30], [0,-10], [0,-5]) . Quiero dividir las filas en partes y contar el número de filas en esta parte. Si la longitud de las filas no es 6, elimine todo el fragmento; de lo contrario, conserve este fragmento.

Mis códigos en bruto:

 v1_ls = df.v1.unique() v2_ls = df.v2.unique() for i, j in v1_ls, v2_ls: chunk[i] = df[(df['v1'] == v1_ls[i]) & df['v2'] == v2_ls[j]] if len(chunk[i])!= 6: df = df[df != chunk[i]] else: pass 

Rendimiento esperado:

  v1 v2 v3 0 -30 -15 0 -30 -7.5 0 -30 -11.25 0 -30 -13.125 0 -30 -14.0625 0 -30 -13.59375 0 -10 -5 0 -10 -7.5 0 -10 -6.25 0 -10 -5.625 0 -10 -5.9375 0 -10 -6.09375 

¡Gracias!

Creo que en v1 y v2 no hay NaN s, así que use transform + size :

 df = df[df.groupby(['v1', 'v2'])['v2'].transform('size') == 6] print (df) v1 v2 v3 0 0 -30 -15.00000 1 0 -30 -7.50000 2 0 -30 -11.25000 3 0 -30 -13.12500 4 0 -30 -14.06250 5 0 -30 -13.59375 6 0 -10 -5.00000 7 0 -10 -7.50000 8 0 -10 -6.25000 9 0 -10 -5.62500 10 0 -10 -5.93750 11 0 -10 -6.09375 

Detalle:

 print (df.groupby(['v1', 'v2'])['v2'].transform('size') == 6) 0 True 1 True 2 True 3 True 4 True 5 True 6 True 7 True 8 True 9 True 10 True 11 True 12 False 13 False 14 False Name: v2, dtype: bool 

Desafortunadamente, el filter es realmente lento, por lo que si necesita un mejor rendimiento, use la transform

 np.random.seed(123) N = 1000000 L = list('abcdefghijkl') df = pd.DataFrame({'v1': np.random.choice(L, N), 'v2':np.random.randint(10000,size=N), 'value':np.random.randint(1000,size=N), 'value2':np.random.randint(5000,size=N)}) df = df.sort_values(['v1','v2']).reset_index(drop=True) print (df.head(10)) In [290]: %timeit df.groupby(['v1', 'v2']).filter(lambda x: len(x) == 6) 1 loop, best of 3: 12.1 s per loop In [291]: %timeit df[df.groupby(['v1', 'v2'])['v2'].transform('size') == 6] 1 loop, best of 3: 176 ms per loop In [292]: %timeit df[df.groupby(['v1', 'v2']).v2.transform('count').eq(6)] 10 loops, best of 3: 175 ms per loop 

 N = 1000000 ngroups = 1000 df = pd.DataFrame(dict(A = np.random.randint(0,ngroups,size=N),B=np.random.randn(N))) In [299]: %timeit df.groupby('A').filter(lambda x: len(x) > 1000) 1 loop, best of 3: 330 ms per loop In [300]: %timeit df[df.groupby(['A'])['A'].transform('size') > 1000] 10 loops, best of 3: 101 ms per loop 

Advertencia

Los resultados no abordan el rendimiento dado el número de grupos, lo que afectará mucho los tiempos de algunas de estas soluciones.

Puedes usar el método de filter grupo:

 In [11]: df.groupby(['v1', 'v2']).filter(lambda x: len(x) == 6) Out[11]: v1 v2 v3 0 0 -30 -15.00000 1 0 -30 -7.50000 2 0 -30 -11.25000 3 0 -30 -13.12500 4 0 -30 -14.06250 5 0 -30 -13.59375 6 0 -10 -5.00000 7 0 -10 -7.50000 8 0 -10 -6.25000 9 0 -10 -5.62500 10 0 -10 -5.93750 11 0 -10 -6.09375 

Use groupby + count/size :

 df.groupby(['v1', 'v2']).v3.transform('count') 0 6.0 1 6.0 2 6.0 3 6.0 4 6.0 5 6.0 6 6.0 7 6.0 8 6.0 9 6.0 10 6.0 11 6.0 12 3.0 13 3.0 14 3.0 Name: v3, dtype: float64 

Usa la máscara para filtrar df :

 df = df[df.groupby(['v1', 'v2']).v3.transform('count').eq(6)] # == 6 df v1 v2 v3 0 0 -30 -15.00000 1 0 -30 -7.50000 2 0 -30 -11.25000 3 0 -30 -13.12500 4 0 -30 -14.06250 5 0 -30 -13.59375 6 0 -10 -5.00000 7 0 -10 -7.50000 8 0 -10 -6.25000 9 0 -10 -5.62500 10 0 -10 -5.93750 11 0 -10 -6.09375 

count no cuenta los NaN , mientras que el size sí lo hace. Usa lo que sea apropiado para ti.