2012-07-10 10 views
47

Chciałbym filtrować wiersze za pomocą funkcji każdego wiersza, np.pandy: złożony filtr w wierszach DataFrame

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

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

lub innej bardziej złożonym contrived przykład

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

Jak mogę to zrobić?

Odpowiedz

70

Możesz to zrobić, używając DataFrame.apply, z którego h stosuje funkcję wzdłuż danej osi,

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

Nie ma potrzeby stosowania "apply" w tej sytuacji. Regularny indeks boolowski będzie działał dobrze. 'df [df ['b]> df [' c ']]'. Jest bardzo mało sytuacji, które faktycznie wymagają 'apply', a nawet kilka, które potrzebują tego z' axis = 1' –

8

Załóżmy miałem DataFrame następująco:

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 

mogę używać grzech i DataFrame.prod stworzyć logiczną maskę:

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 

Następnie użyć maski do wyboru z DataFrame :

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

rzeczywiście, był to chyba zły przykład: 'np.sin' automatycznie rozsyła do wszystkich elementów. Co się stanie, jeśli zastąpię go mniej inteligentną funkcją, która może obsługiwać tylko jedno wejście naraz? – duckworthd

1

canot wypowiedzieć się na temat duckworthd's answer, ale nie działa idealnie. wywala to kiedy dataframe jest pusty:

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

Wyjścia:

ValueError: Must pass DataFrame with boolean values only 

Dla mnie to wygląda na błąd w pand, ponieważ {} jest definitywnie ważny zbiór wartości logicznych.