2017-08-28 2 views
3

Je suis en train de filtrer une trame de données de pandas géants à l'aide des seuils pour trois colonnesfiltrage Dynamiquement une trame de données de pandas géants

import pandas as pd 
df = pd.DataFrame({"A" : [6, 2, 10, -5, 3], 
        "B" : [2, 5, 3, 2, 6], 
        "C" : [-5, 2, 1, 8, 2]}) 
df = df.loc[(df.A > 0) & (df.B > 2) & (df.C > -1)].reset_index(drop = True) 

df 
    A B C 
0 2 5 2 
1 10 3 1 
2 3 6 2 

Cependant, je veux le faire dans une fonction où sont donnés les noms des colonnes et leurs seuils à moi dans un dictionnaire. Voici mon premier essai qui fonctionne bien. Essentiellement, je suis en train de filtre à l'intérieur de variable cond et exécutez simplement:

df = pd.DataFrame({"A" : [6, 2, 10, -5, 3], 
        "B" : [2, 5, 3, 2, 6], 
        "C" : [-5, 2, 1, 8, 2]}) 
limits_dic = {"A" : 0, "B" : 2, "C" : -1} 
cond = "df = df.loc[" 
for key in limits_dic.keys(): 
    cond += "(df." + key + " > " + str(limits_dic[key])+ ") & " 
cond = cond[:-2] + "].reset_index(drop = True)" 
exec(cond) 
df 
    A B C 
0 2 5 2 
1 10 3 1 
2 3 6 2 

Maintenant, enfin je mets tout à l'intérieur d'une fonction et il cesse de fonctionner (peut-être exec fonction n'aime pas être utilisé dans une fonction!):

df = pd.DataFrame({"A" : [6, 2, 10, -5, 3], 
        "B" : [2, 5, 3, 2, 6], 
        "C" : [-5, 2, 1, 8, 2]}) 
limits_dic = {"A" : 0, "B" : 2, "C" : -1} 
def filtering(df, limits_dic): 
    cond = "df = df.loc[" 
    for key in limits_dic.keys(): 
     cond += "(df." + key + " > " + str(limits_dic[key])+ ") & " 
    cond = cond[:-2] + "].reset_index(drop = True)" 
    exec(cond) 
    return(df) 

df = filtering(df, limits_dic) 
df 
    A B C 
0 6 2 -5 
1 2 5 2 
2 10 3 1 
3 -5 2 8 
4 3 6 2 

Je sais que la fonction exec agit différemment lorsqu'il est utilisé dans une fonction, mais ne savait pas comment faire face au problème. Aussi, je me demande s'il doit y avoir une manière plus élégante de définir une fonction pour faire le filtrage donné à deux entrées: 1) df et 2) limits_dic = {"A" : 0, "B" : 2, "C" : -1}. J'apprécierais toutes les pensées à ce sujet.

Répondre

9

Si vous essayez de créer une requête dynamique, il existe des moyens plus simples. Voici une en utilisant une compréhension de la liste et str.join:

query = ' & '.join(['{} > {}'.format(k, v) for k, v in limits_dic.items()]) 
print(query) 

'A > 0 & C > -1 & B > 2' 

passer la chaîne de requête pour df.query, il est destiné à cet effet très:

out = df.query(query) 
print(out) 

    A B C 
1 2 5 2 
2 10 3 1 
4 3 6 2 

Vous pouvez également utiliser df.eval si vous souhaitez obtenir un masque booléen pour votre requête, puis l'indexation devient simple après cela:

mask = df.eval(query) 
print(mask) 

0 False 
1  True 
2  True 
3 False 
4  True 
dtype: bool 

out = df[mask] 
print(out) 

    A B C 
1 2 5 2 
2 10 3 1 
4 3 6 2 
+2

^mérite plus upvote! – piRSquared

+0

@ cᴏʟᴅsᴘᴇᴇᴅ Votre suggestion a parfaitement fonctionné. Utiliser 'exec' n'était certainement pas le meilleur moyen de le faire. Cela étant dit, il est étrange que 'exec' agisse différemment à l'intérieur d'une fonction. Peu importe, je vais m'en tenir aux méthodes 'query' et' eval' de 'pandas'. Merci encore pour votre réponse approfondie. – ahoosh