2012-07-10 16 views
47

Me gustaría filtrar filas por una función de cada fila, p. Ej.pandas: filtro complejo en filas de DataFrame

def f(row): 
    return sin(row['velocity'])/np.prod(['masses']) > 5 

df = pandas.DataFrame(...) 
filtered = df[apply_to_all_rows(df, f)] 

o para otro ejemplo más complejo, artificiosa,

def g(row): 
    if row['col1'].method1() == 1: 
    val = row['col1'].method2()/row['col1'].method3(row['col3'], row['col4']) 
    else: 
    val = row['col2'].method5(row['col6']) 
    return np.sin(val) 

df = pandas.DataFrame(...) 
filtered = df[apply_to_all_rows(df, g)] 

¿Cómo puedo hacer eso?

Respuesta

70

Usted puede hacer esto utilizando DataFrame.apply, whic h aplica una función a lo largo de un eje dado,

In [3]: df = pandas.DataFrame(np.random.randn(5, 3), columns=['a', 'b', 'c']) 

In [4]: df 
Out[4]: 
      a   b   c 
0 -0.001968 -1.877945 -1.515674 
1 -0.540628 0.793913 -0.983315 
2 -1.313574 1.946410 0.826350 
3 0.015763 -0.267860 -2.228350 
4 0.563111 1.195459 0.343168 

In [6]: df[df.apply(lambda x: x['b'] > x['c'], axis=1)] 
Out[6]: 
      a   b   c 
1 -0.540628 0.793913 -0.983315 
2 -1.313574 1.946410 0.826350 
3 0.015763 -0.267860 -2.228350 
4 0.563111 1.195459 0.343168 
+1

No es necesario 'aplicar' en esta situación. Un índice booleano regular funcionará bien. 'df [df ['b]> df [' c ']]'. Hay muy pocas situaciones que realmente requieran 'apply' e incluso algunas que lo necesiten con' axis = 1' –

8

Supongamos que tenía una trama de datos de la siguiente manera:

In [39]: df 
Out[39]: 
     mass1  mass2 velocity 
0 1.461711 -0.404452 0.722502 
1 -2.169377 1.131037 0.232047 
2 0.009450 -0.868753 0.598470 
3 0.602463 0.299249 0.474564 
4 -0.675339 -0.816702 0.799289 

puedo usar pecado y DataFrame.prod para crear una máscara booleana:

In [40]: mask = (np.sin(df.velocity)/df.ix[:, 0:2].prod(axis=1)) > 0 

In [41]: mask 
Out[41]: 
0 False 
1 False 
2 False 
3  True 
4  True 

continuación, utilizar la máscara para seleccionar de la trama de datos :

In [42]: df[mask] 
Out[42]: 
     mass1  mass2 velocity 
3 0.602463 0.299249 0.474564 
4 -0.675339 -0.816702 0.799289 
+2

realidad, esto era probablemente un mal ejemplo: 'np.sin' envía automáticamente a todos los elementos. ¿Qué sucede si lo reemplazo con una función menos inteligente que solo podría manejar una entrada a la vez? – duckworthd

1

Yo canot comentar sobre duckworthd's answer, pero no es perfecto estado de funcionamiento. Se estrella cuando la trama de datos está vacía:

df = pandas.DataFrame(columns=['a', 'b', 'c']) 
df[df.apply(lambda x: x['b'] > x['c'], axis=1)] 

Salidas:

ValueError: Must pass DataFrame with boolean values only 

A mí parece un error en pandas, ya que {} es definitivamente un conjunto válido de valores booleanos.

Cuestiones relacionadas