2
votes

Filtre Dataframe avec multi-index: retourne toutes les lignes au niveau d'index supérieur des filtres de valeur donnés

Je recherche la syntaxe pour renvoyer toutes les données de premier niveau en fonction de plusieurs critères de valeur finale. J'ai lu et trouvé des solutions de filtrage avec .loc ou .xs mais je peux tout à fait obtenir la syntaxe pour ce que je veux. J'utilise pour travailler avec xpath et je veux juste // A [B [@ x = 1 et @ y = 2]] en substance.

J'ai essayé beaucoup de permutations de syntaxe avec lesquelles je suis familier avec les formes de df.loc df.xs mutlti [], un peu avec df.index.get_level_values ​​(), etc ...

Donc à partir d'un dataframe comme celui-ci: x y UN B a b 1 2 a f 4 5 a c 3 4 b d 1 5
b c 1 2 c d 2 3

Je souhaite rechercher une combinaison spécifique de x et y et renvoyer toutes les lignes au niveau de l'index A.

Donc je veux x = 1 et y = 2 et obtenir

x y UN B a b 1 2 a f 4 5 a c 3 4 b d 1 5 b c 1 2

Parce qu'au moins 1 seule ligne d'un A donné correspond à

Et encore mieux, une solution plus générale serait de rechercher une valeur x d'une valeur B particulière et une valeur y d'un B. différent particulier

(pour plus de clarté): Je veux dire par là qu'au lieu des valeurs de niveau final que je recherche, je peux être intéressé par la combinaison uniquement de valeurs B spécifiques. Ci-dessous, j'ai B 1 = b et x = 3. donc je mélange la correspondance d'une valeur avec la correspondance d'une valeur d'index. Alors qu'avant, je limitais deux valeurs finales. Encore une fois, j'envisage cela dans xpath comme // A [B [local-name () == b et @ x = 3] et B [local-name () == f et @ y = 5]] < / code> (je pense que j'ai bien compris).

Par exemple, B 1 = b: x = 3 et B 2 = f: y = 5. Retour:

x y UN B a b 1 2 a f 4 5 a c 3 4

Merci!


1 commentaires

Pouvez-vous énoncer plus clairement la deuxième partie de votre problème? Toutes les conditions doivent-elles être remplies et dans quelle combinaison? Ou filtrez-vous toujours par A ?


3 Réponses :


2
votes

Vous pouvez query code > votre dataframe en quelques étapes:

df = pd.DataFrame([['a', 'b', 1, 2], ['a', 'f', 4, 5], ['a', 'c', 3, 4],
                   ['b', 'd', 1, 5], ['b', 'c', 1, 2], ['c', 'd', 2, 3]],
                  columns=['A', 'B', 'x', 'y'])

df = df.set_index(['A', 'B'])

Configuration

A_idx = df.query('x == 1 & y == 2').index.get_level_values('A')
res = df.query('A in @A_idx')

print(res)

#      x  y
# A B      
# a b  1  2
#   f  4  5
#   c  3  4
# b d  1  5
#   c  1  2


4 commentaires

Bonne année :-)


Cela a très bien fonctionné pour cet exemple d'ensemble de données. Est-il possible d'ajuster pour accueillir un index avec un espace ... "A 2" au lieu de "A" par exemple? en lisant rapidement, il semble que les espaces et les requêtes ne s'entendent pas. Merci et bonne année!)


@DontJudgeMyADD, vous pouvez toujours utiliser loc , par exemple remplacer df.query ('x == 1 & y == 2') par df.loc [df ['x']. eq (1) & df ['y'] .eq (2)) . Et bonne année!


@ W-B, bonne année!



1
votes

Vous pouvez utiliser groupby on level = 'A' et filter après avoir créé une colonne flag pour chaque colonne x et y si les valeurs que vous recherchez s'y trouvent avec numpy .where .

print (df.groupby(level='A').filter(lambda dfg: (dfg.flagx & dfg.flagy).any() )
         .drop(['flagx','flagy'],axis=1))
     x  y
A B      
b d  1  5
  c  1  2

Maintenant, si vous voulez que x et y remplissent les conditions pour n'importe quelle valeur de B et le même A , vous pouvez utiliser any sur chaque indicateur et rechercher les deux avec & :

print (df.groupby(level='A').filter(lambda dfg: dfg.flagx.any() & dfg.flagy.any() )
         .drop(['flagx','flagy'],axis=1))
     x  y
A B      
a b  1  2
  f  4  5
  c  3  4
b d  1  5
  c  1  2

Si vous voulez que les deux conditions sur x et y soient remplies sur la même ligne, vous pouvez faites-le en changeant la position du any et du & dans le filter:

#using @jpp setup
import numpy as np
df['flagx'] = np.where(df.x == 1,1,0)
df['flagy'] = np.where(df.y == 5,1,0)


3 commentaires

Bonne année à toi :-)


@ W-B vous aussi, et beaucoup de réponses sur stackoverflow :-)


Merci, je l'ai fait fonctionner. Cela m'a également permis de gérer assez facilement un index avec un espace. Merci! Bonne année!



2
votes

Utilisation de groupby + transform + any

df[df.eq({'x':1,'y':2}).groupby(level=0).transform('any').any(1)]
     x  y
A B      
a b  1  2
  f  4  5
  c  3  4
b d  1  5
  c  1  2


4 commentaires

Bien pour la méthode eq avec les deux colonnes dans un dict :-)


Salut! qui renvoie une table vide pour moi. Je manque la configuration de dict, non? Merci


@DontJudgeMyADD {'x': 1, 'y': 2} c'est le dict que j'utilise. et travaille bien de mon côté


Merci @ W-B, je ne sais pas pourquoi cela ne fonctionne pas pour moi. Je l'ai copié-collé directement et je ne peux pas faire en sorte que .eq () prenne plus d'une entrée comme vous l'avez fait. Je cherche depuis un bon moment et je ne trouve pas non plus un bon tutoriel sur l'utilisation de .eq comme celui-ci.