J'ai un scénario dans lequel un utilisateur souhaite appliquer plusieurs filtres à un objet Pandas DataFrame ou Series. Essentiellement, je souhaite enchaîner efficacement un ensemble de filtrages (opérations de comparaison) qui sont spécifiés au moment de l'exécution par l'utilisateur.
Les filtres doivent être additifs (c'est-à-dire que chacun appliqué doit restreindre les résultats).
J'utilise actuellement reindex()
mais cela crée un nouvel objet à chaque fois et copie les données sous-jacentes (si je comprends correctement la documentation). Donc, cela pourrait être vraiment inefficace lors du filtrage d'une grande série ou DataFrame.
Je pense que l'utilisation de apply()
, map()
ou quelque chose de similaire pourrait être mieux. Je suis assez nouveau sur Pandas, alors j'essaie toujours de comprendre tout.
TL; DR
Je veux prendre un dictionnaire de la forme suivante et 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 en filtrant simplement 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
Encore une fois, le «problème» avec mon approche ci-dessus est que je pense qu'il y a beaucoup de copies éventuellement inutiles des données pour les étapes intermédiaires.
En outre, je voudrais développer cela afin que le dictionnaire transmis puisse inclure les colonnes sur lesquelles l'opérateur et filtrer un DataFrame entier en fonction du dictionnaire d'entrée. Cependant, je suppose que tout ce qui fonctionne pour la série peut être facilement étendu à un DataFrame.
df.query
et pd.eval
semblent bien adaptés à votre cas d'utilisation. Pour plus d'informations sur la pd.eval()
famille de fonctions, leurs caractéristiques et leurs cas d'utilisation, veuillez visiter Évaluation des expressions dynamiques dans les pandas à l'aide de pd.eval () .