J'ai un scénario dans lequel un utilisateur veut appliquer plusieurs filtres à un objet DataFrame ou Series Pandas . Essentiellement, je veux enchaîner efficacement un ensemble de filtrages (opérations de comparaison) qui sont spécifiés à l'exécution par l'utilisateur.
- Les filtres doivent être additif (c'est-à-dire que chaque application devrait réduire les résultats).
- J'utilise actuellement
reindex()
(comme ci-dessous) mais cela crée un nouvel objet à chaque fois et copie les données sous-jacentes (si je comprends bien la documentation). Je veux éviter cette copie inutile car elle serait vraiment inefficace lors du filtrage d'une grande série ou d'un DataFrame. - Je pense qu'en utilisant
apply()
,map()
ou quelque chose de similaire pourrait être mieux. Je suis assez novice en matière de Pandas et j'essaie encore de m'y retrouver. - De plus, j'aimerais étendre cela pour que le dictionnaire transmis peut inclure les colonnes sur lesquelles opérer et filtrer un DataFrame entier sur la base du dictionnaire d'entrée. Cependant, je suppose que ce qui fonctionne pour une série peut facilement être étendu à un cadre de données.
TL;DR
Je veux prendre un dictionnaire de la forme suivante, appliquer chaque opération à un objet Series donné et renvoyer un objet Series "filtré".
relops = {'>=': [1], '<=': [1]}
Exemple long
Je vais commencer par un exemple de ce que j'ai actuellement et filtrer un seul objet Series. Voici la fonction que j'utilise actuellement :
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
L'utilisateur fournit un dictionnaire avec les opérations qu'il souhaite effectuer :
>>> 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
Une fois de plus, le "problème" avec mon approche ci-dessus est que je pense qu'il y a beaucoup de copies inutiles des données pour les étapes intermédiaires.