2 votes

Pandas : comment effectuer une sélection conditionnelle sur MultiIndex ?

Voici le exemple de fichier de données et j'ai effectué l'opération suivante dans ipython notebook :

!curl -O http://pbpython.com/extras/sales-funnel.xlsx

df = pd.read_excel('./sales-funnel.xlsx')
df['Status'] = df['Status'].astype('category')
df["Status"].cat.set_categories(["won","pending","presented","declined"],inplace=True)

table = pd.pivot_table(df,
               index=['Manager', 'Status'],
               values=['Price', 'Quantity'],
               columns=['Product'],
               aggfunc={'Price':[np.sum, np.mean], 'Quantity':len},
               fill_value=0
              )

Voici à quoi ressemblent les données dans table :

enter image description here

Je veux sélectionner (Manager=="Debra Henley") & (Status=="won") et il fonctionne avec le query méthode :

table.query('(Manager=="Debra Henley") & (Status=="won")')

Mais comment effectuer la même sélection avec loc ? J'ai essayé mais cela ne fonctionne pas :

table.loc[['Debra Henley', 'won']]

Qu'est-ce que vous utilisez habituellement avec MultiIndex ? Quelle est la meilleure façon de le faire ?


Mise à jour : deux solutions ont été trouvées jusqu'à présent :

table.xs(('Debra Henley','won'), level=('Manager', 'Status'))
table.loc[[('Debra Henley', 'won')]]

Donc je suppose tuples doit être utilisé à la place de lists lors de l'indexation avec MultiIndex ?

3voto

piRSquared Points 159

Votre réponse canonique est fournie par @ScottBoston.

J'ajouterai ceci pour l'ampleur et la perspective, en plus de ce que @jezrael a dit. IndexSlice approche.
Vous pouvez également utiliser pd.DataFrame.xs pour prendre une coupe transversale

table.xs(['Debra Henley', 'won'])

                Product    
Quantity  len   CPU                1
                Maintenance        0
                Monitor            0
                Software           0
Price     mean  CPU            65000
                Maintenance        0
                Monitor            0
                Software           0
          sum   CPU            65000
                Maintenance        0
                Monitor            0
                Software           0
Name: (Debra Henley, won), dtype: int64

2voto

jezrael Points 290608

Pour des sélections plus simples (seulement index ou seulement colonnes), utilisez xs l'approche ou la sélection par tuples .

Une autre solution plus générale avec trancheurs :

idx = pd.IndexSlice
#output is df
print (table.loc[[idx['Debra Henley','won']]])
                    Quantity                               Price              \
                         len                                mean               
Product                  CPU Maintenance Monitor Software    CPU Maintenance   
Manager      Status                                                            
Debra Henley won           1           0       0        0  65000           0   

                                        sum                               
Product             Monitor Software    CPU Maintenance Monitor Software  
Manager      Status                                                       
Debra Henley won          0        0  65000           0       0        0

idx = pd.IndexSlice
#output is series
print (table.loc[idx['Debra Henley','won'],:])
Quantity  len   CPU                1
                Maintenance        0
                Monitor            0
                Software           0
Price     mean  CPU            65000
                Maintenance        0
                Monitor            0
                Software           0
          sum   CPU            65000
                Maintenance        0
                Monitor            0
                Software           0
Name: (Debra Henley, won), dtype: int64

Mais c'est mieux pour les sélections plus compliquées - si vous avez besoin de filtrer l'index et les colonnes ensemble - un seul xs ne fonctionne pas :

idx = pd.IndexSlice
#select all rows where first level is Debra Henley in index and 
#in columns second level is len and sum
print (table.loc[idx['Debra Henley',:], idx[:, ['len', 'sum'], :]])
                       Quantity                               Price  \
                            len                                 sum   
Product                     CPU Maintenance Monitor Software    CPU   
Manager      Status                                                   
Debra Henley won              1           0       0        0  65000   
             pending          1           2       0        0  40000   
             presented        1           0       0        2  30000   
             declined         2           0       0        0  70000   

Product                Maintenance Monitor Software  
Manager      Status                                  
Debra Henley won                 0       0        0  
             pending         10000       0        0  
             presented           0       0    20000  
             declined            0       0        0

1voto

Scott Boston Points 48995

Oui, vous pouvez utiliser :

table.loc[[('Debra Henley', 'won')]]

pour retourner un cadre de données pandas ou vous pouvez utiliser :

table.loc[('Debra Henley','won')]

pour retourner une série de pandas.

Vous pouvez vous référer à la este documentation.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X