Auswahl aus Pandas mit mehreren Indizes


89

Ich habe einen Multi-Index-Datenrahmen mit den Spalten 'A' und 'B'.

Gibt es eine Möglichkeit, Zeilen durch Filtern nach einer Spalte des Multi-Index auszuwählen, ohne den Index auf einen einzelnen Spaltenindex zurückzusetzen?

Beispielsweise.

# has multi-index (A,B)
df
#can I do this? I know this doesn't work because the index is multi-index so I need to     specify a tuple

df.ix[df.A ==1]


Verwandte: Wählen Sie Zeilen in Pandas MultiIndex DataFrame (eine breite Diskussion zum gleichen Thema von mir).
cs95

Antworten:


128

Eine Möglichkeit ist die Verwendung der get_level_valuesIndexmethode:

In [11]: df
Out[11]:
     0
A B
1 4  1
2 5  2
3 6  3

In [12]: df.iloc[df.index.get_level_values('A') == 1]
Out[12]:
     0
A B
1 4  1

In 0.13 können Sie xsmit drop_levelArgument verwenden :

df.xs(1, level='A', drop_level=False) # axis=1 if columns

Hinweis: Wenn dies eine Spalte MultiIndex anstelle eines Index wäre, könnten Sie dieselbe Technik verwenden:

In [21]: df1 = df.T

In [22]: df1.iloc[:, df1.columns.get_level_values('A') == 1]
Out[22]:
A  1
B  4
0  1

46

Sie können auch verwenden, querywas meiner Meinung nach sehr lesbar und einfach zu verwenden ist:

import pandas as pd

df = pd.DataFrame({'A': [1, 2, 3, 4], 'B': [10, 20, 50, 80], 'C': [6, 7, 8, 9]})
df = df.set_index(['A', 'B'])

      C
A B    
1 10  6
2 20  7
3 50  8
4 80  9

Für das, was Sie sich vorgestellt haben, können Sie jetzt einfach Folgendes tun:

df.query('A == 1')

      C
A B    
1 10  6

Sie können auch komplexere Abfragen mit verwenden and

df.query('A >= 1 and B >= 50')

      C
A B    
3 50  8
4 80  9

und or

df.query('A == 1 or B >= 50')

      C
A B    
1 10  6
3 50  8
4 80  9

Sie können auch auf verschiedenen Indexebenen abfragen , z

df.query('A == 1 or C >= 8')

wird zurückkehren

      C
A B    
1 10  6
3 50  8
4 80  9

Wenn Sie Variablen in Ihrer Abfrage verwenden möchten, können Sie Folgendes verwenden@ :

b_threshold = 20
c_threshold = 8

df.query('B >= @b_threshold and C <= @c_threshold')

      C
A B    
2 20  7
3 50  8

1
Tolle Antwort, viel besser lesbar. Wissen Sie, ob es möglich ist, zwei Felder auf verschiedenen df.query('A == 1 or C >= 8')
Indexebenen

@obchardon: Das scheint gut zu funktionieren; Ich habe meine Antwort anhand Ihres Beispiels bearbeitet.
Cleb

1
Ich habe Zeiten und Zeichenfolgen als Multiindex, was Probleme im Zeichenfolgenausdruck verursacht. Funktioniert jedoch df.query()problemlos mit Variablen, wenn auf sie mit einem '@' innerhalb des Ausdrucks in der Abfrage verwiesen wird, z. B. df.query('A == @varfür eine Variable varin der Umgebung.
Solly

@Solly: Danke, ich habe dies der Antwort hinzugefügt.
Cleb

Wo ist die Multi-Indizierung hier?
Lamma

32

Sie können verwenden DataFrame.xs():

In [36]: df = DataFrame(np.random.randn(10, 4))

In [37]: df.columns = [np.random.choice(['a', 'b'], size=4).tolist(), np.random.choice(['c', 'd'], size=4)]

In [38]: df.columns.names = ['A', 'B']

In [39]: df
Out[39]:
A      b             a
B      d      d      d      d
0 -1.406  0.548 -0.635  0.576
1 -0.212 -0.583  1.012 -1.377
2  0.951 -0.349 -0.477 -1.230
3  0.451 -0.168  0.949  0.545
4 -0.362 -0.855  1.676 -2.881
5  1.283  1.027  0.085 -1.282
6  0.583 -1.406  0.327 -0.146
7 -0.518 -0.480  0.139  0.851
8 -0.030 -0.630 -1.534  0.534
9  0.246 -1.558 -1.885 -1.543

In [40]: df.xs('a', level='A', axis=1)
Out[40]:
B      d      d
0 -0.635  0.576
1  1.012 -1.377
2 -0.477 -1.230
3  0.949  0.545
4  1.676 -2.881
5  0.085 -1.282
6  0.327 -0.146
7  0.139  0.851
8 -1.534  0.534
9 -1.885 -1.543

Wenn Sie die AEbene drop_levelbeibehalten möchten (das Schlüsselwortargument ist nur ab Version 0.13.0 verfügbar):

In [42]: df.xs('a', level='A', axis=1, drop_level=False)
Out[42]:
A      a
B      d      d
0 -0.635  0.576
1  1.012 -1.377
2 -0.477 -1.230
3  0.949  0.545
4  1.676 -2.881
5  0.085 -1.282
6  0.327 -0.146
7  0.139  0.851
8 -1.534  0.534
9 -1.885 -1.543

1
Ha, ich hatte gerade meine Antwort damit aktualisiert. Hinweis: Nur in 0.13 verfügbar.
Andy Hayden

Oh, gut zu wissen. Ich kann mich nie erinnern, welche kleinen Annehmlichkeiten in jeder Version hinzugefügt wurden.
Phillip Cloud

Lol, in der Tat ist diese Frage ein Betrug der, die diese Bequemlichkeit inspiriert hat! :)
Andy Hayden

11

Das Verständnis , wie man Zugang Multi-indexierte Pandas Datenrahmen können Sie mit allen Arten von Aufgaben wie das helfen.

Kopieren Sie diese und fügen Sie sie in Ihren Code ein, um ein Beispiel zu generieren:

# hierarchical indices and columns
index = pd.MultiIndex.from_product([[2013, 2014], [1, 2]],
                                   names=['year', 'visit'])
columns = pd.MultiIndex.from_product([['Bob', 'Guido', 'Sue'], ['HR', 'Temp']],
                                     names=['subject', 'type'])

# mock some data
data = np.round(np.random.randn(4, 6), 1)
data[:, ::2] *= 10
data += 37

# create the DataFrame
health_data = pd.DataFrame(data, index=index, columns=columns)
health_data

Wird Ihnen einen Tisch wie diesen geben:

Geben Sie hier die Bildbeschreibung ein

Standardzugriff nach Spalte

health_data['Bob']
type       HR   Temp
year visit      
2013    1   22.0    38.6
        2   52.0    38.3
2014    1   30.0    38.9
        2   31.0    37.3


health_data['Bob']['HR']
year  visit
2013  1        22.0
      2        52.0
2014  1        30.0
      2        31.0
Name: HR, dtype: float64

# filtering by column/subcolumn - your case:
health_data['Bob']['HR']==22
year  visit
2013  1         True
      2        False
2014  1        False
      2        False

health_data['Bob']['HR'][2013]    
visit
1    22.0
2    52.0
Name: HR, dtype: float64

health_data['Bob']['HR'][2013][1]
22.0

Zugriff per Zeile

health_data.loc[2013]
subject Bob Guido   Sue
type    HR  Temp    HR  Temp    HR  Temp
visit                       
1   22.0    38.6    40.0    38.9    53.0    37.5
2   52.0    38.3    42.0    34.6    30.0    37.7

health_data.loc[2013,1] 
subject  type
Bob      HR      22.0
         Temp    38.6
Guido    HR      40.0
         Temp    38.9
Sue      HR      53.0
         Temp    37.5
Name: (2013, 1), dtype: float64

health_data.loc[2013,1]['Bob']
type
HR      22.0
Temp    38.6
Name: (2013, 1), dtype: float64

health_data.loc[2013,1]['Bob']['HR']
22.0

Multi-Index schneiden

idx=pd.IndexSlice
health_data.loc[idx[:,1], idx[:,'HR']]
    subject Bob Guido   Sue
type    HR  HR  HR
year    visit           
2013    1   22.0    40.0    53.0
2014    1   30.0    52.0    45.0

Dies gibt ValueError: cannot handle a non-unique multi-index!Fehler
Coddy

5

Sie können verwenden DataFrame.loc:

>>> df.loc[1]

Beispiel

>>> print(df)
       result
A B C        
1 1 1       6
    2       9
  2 1       8
    2      11
2 1 1       7
    2      10
  2 1       9
    2      12

>>> print(df.loc[1])
     result
B C        
1 1       6
  2       9
2 1       8
  2      11

>>> print(df.loc[2, 1])
   result
C        
1       7
2      10

Dies ist der beste der modernen Ansätze IMO, bei denen df.loc [2, 1] ['result'] mehrspaltig behandelt
Michael

Dies funktioniert aus irgendeinem Grund mit einer beliebigen Anzahl von Ganzzahlen. zBdf.loc[0], df.loc[1]....df.loc[n]
Coddy

2

Eine weitere Option ist:

filter1 = df.index.get_level_values('A') == 1
filter2 = df.index.get_level_values('B') == 4

df.iloc[filter1 & filter2]
Out[11]:
     0
A B
1 4  1
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.