Mam scenariusz, w którym użytkownik chce zastosować kilka filtrów do obiektu Pandas DataFrame lub Series. Zasadniczo chcę wydajnie łączyć kilka operacji filtrowania (operacji porównania), które są określane w czasie wykonywania przez użytkownika.
Filtry powinny być addytywne (każdy zastosowany powinien zawęzić wyniki).
Obecnie używam, reindex()
ale za każdym razem tworzy to nowy obiekt i kopiuje podstawowe dane (jeśli dobrze rozumiem dokumentację). Tak więc może to być naprawdę nieefektywne podczas filtrowania dużej serii lub ramki DataFrame.
Myślę, że za pomocą apply()
, map()
lub coś podobnego mogłoby być lepiej. Jestem całkiem nowy w Pandach, więc wciąż próbuję wszystko ogarnąć.
TL; DR
Chcę wziąć słownik w poniższej formie i zastosować każdą operację do danego obiektu Series i zwrócić „przefiltrowany” obiekt Series.
relops = {'>=': [1], '<=': [1]}
Długi przykład
Zacznę od przykładu tego, co mam obecnie i tylko filtrując pojedynczy obiekt Series. Poniżej znajduje się funkcja, której obecnie używam:
def apply_relops(series, relops):
"""
Pass dictionary of relational operators to perform on given series object
"""
for op, vals in relops.iteritems():
op_func = ops[op]
for val in vals:
filtered = op_func(series, val)
series = series.reindex(series[filtered])
return series
Użytkownik udostępnia słownik z operacjami, które chce wykonać:
>>> df = pandas.DataFrame({'col1': [0, 1, 2], 'col2': [10, 11, 12]})
>>> print df
>>> print df
col1 col2
0 0 10
1 1 11
2 2 12
>>> from operator import le, ge
>>> ops ={'>=': ge, '<=': le}
>>> apply_relops(df['col1'], {'>=': [1]})
col1
1 1
2 2
Name: col1
>>> apply_relops(df['col1'], relops = {'>=': [1], '<=': [1]})
col1
1 1
Name: col1
Ponownie, „problem” z moim powyższym podejściem polega na tym, że wydaje mi się, że jest dużo prawdopodobnie niepotrzebnego kopiowania danych w krokach pośrednich.
Chciałbym również rozszerzyć to, aby przekazywany słownik mógł zawierać kolumny do operatora i filtrować całą ramkę DataFrame na podstawie słownika wejściowego. Zakładam jednak, że wszystko, co działa w serii, można łatwo rozszerzyć do ramki DataFrame.
df.query
i pd.eval
wydaje się, że dobrze pasuje do twojego przypadku użycia. Aby uzyskać informacje na temat pd.eval()
rodziny funkcji, ich funkcji i przypadków użycia, odwiedź stronę Ocena wyrażeń dynamicznych w pandach przy użyciu pd.eval () .