Pandas: Eine Ebene aus einem mehrstufigen Spaltenindex löschen?

242

Wenn ich einen mehrstufigen Spaltenindex habe:

>>> cols = pd.MultiIndex.from_tuples([("a", "b"), ("a", "c")])
>>> pd.DataFrame([[1,2], [3,4]], columns=cols)
    ein
   --- + -
    b | c
- + --- + -
0 | 1 | 2
1 | 3 | 4

Wie kann ich die "a" -Ebene dieses Index löschen, sodass ich am Ende Folgendes habe:

    b | c
- + --- + -
0 | 1 | 2
1 | 3 | 4
David Wolever
quelle
3
Es wäre schön, eine DataFrame-Methode zu haben, die dies sowohl für den Index als auch für die Spalten erledigt. Entweder das Löschen oder Auswählen von Indexstufen.
Sören
@ Sören Check out stackoverflow.com/a/56080234/3198568 . droplevelworks kann über den Parameter entweder an mehrstufigen Indizes oder Spalten arbeiten axis.
Irene

Antworten:

306

Sie können verwenden MultiIndex.droplevel:

>>> cols = pd.MultiIndex.from_tuples([("a", "b"), ("a", "c")])
>>> df = pd.DataFrame([[1,2], [3,4]], columns=cols)
>>> df
   a   
   b  c
0  1  2
1  3  4

[2 rows x 2 columns]
>>> df.columns = df.columns.droplevel()
>>> df
   b  c
0  1  2
1  3  4

[2 rows x 2 columns]
DSM
quelle
55
Es ist wahrscheinlich am besten, explizit zu sagen, welches Level fallen gelassen wird. Die Ebenen werden von oben beginnend mit 0 indiziert. >>> df.columns = df.columns.droplevel(0)
Ted Petrou
6
Wenn sich der Index, den Sie >>> df.index = df.index.droplevel(1)
löschen möchten,
7
In Panda Version 0.23.4 df.columns.droplevel()ist nicht mehr verfügbar.
Yoonghm
8
@yoonghm Es ist da, Sie rufen es wahrscheinlich nur für Spalten auf, die keinen Multi-Index haben
Matt Harrison
1
Ich hatte drei Ebenen tief und wollte nur auf die mittlere Ebene fallen. Ich fand, dass das Fallenlassen des niedrigsten (Stufe [2]) und des höchsten (Stufe [0]) am besten funktioniert. >>>df.columns = df.columns.droplevel(2) >>>df.columns = df.columns.droplevel(0)
Kyle C
65

Eine andere Möglichkeit, den Index zu löschen, besteht darin, ein Listenverständnis zu verwenden:

df.columns = [col[1] for col in df.columns]

   b  c
0  1  2
1  3  4

Diese Strategie ist auch nützlich, wenn Sie die Namen beider Ebenen wie im folgenden Beispiel kombinieren möchten, in dem die unterste Ebene zwei Ys enthält:

cols = pd.MultiIndex.from_tuples([("A", "x"), ("A", "y"), ("B", "y")])
df = pd.DataFrame([[1,2, 8 ], [3,4, 9]], columns=cols)

   A     B
   x  y  y
0  1  2  8
1  3  4  9

Wenn Sie die oberste Ebene löschen, bleiben zwei Spalten mit dem Index 'y' übrig. Dies kann vermieden werden, indem die Namen mit dem Listenverständnis verbunden werden.

df.columns = ['_'.join(col) for col in df.columns]

    A_x A_y B_y
0   1   2   8
1   3   4   9

Das ist ein Problem, das ich hatte, nachdem ich einen Groupby gemacht hatte, und es dauerte eine Weile, bis ich diese andere Frage gefunden hatte , die es löste. Ich habe diese Lösung hier an den speziellen Fall angepasst.

Minze
quelle
2
[col[1] for col in df.columns]ist direkter df.columns.get_level_values(1).
Eric O Lebigot
2
Hatte einen ähnlichen Bedarf, bei dem einige Spalten leere Pegelwerte hatten. Verwendet das folgende:[col[0] if col[1] == '' else col[1] for col in df.columns]
Logan
43

Eine andere Möglichkeit, dies zu tun, besteht darin, dfbasierend auf einem Querschnitt von dfmit der .xs- Methode eine Neuzuweisung vorzunehmen .

>>> df

    a
    b   c
0   1   2
1   3   4

>>> df = df.xs('a', axis=1, drop_level=True)

    # 'a' : key on which to get cross section
    # axis=1 : get cross section of column
    # drop_level=True : returns cross section without the multilevel index

>>> df

    b   c
0   1   2
1   3   4
Raumfahrer
quelle
1
Dies funktioniert nur, wenn für eine gesamte Spaltenebene eine einzelne Beschriftung vorhanden ist.
Ted Petrou
1
Funktioniert nicht, wenn Sie die zweite Ebene löschen möchten.
Sören
Dies ist eine gute Lösung, wenn Sie für das gleiche Level in Scheiben schneiden und fallen lassen möchten. Wenn Sie auf der zweiten Ebene schneiden möchten (sagen wir b), dann diese Ebene fallen lassen und mit der ersten Ebene ( a) belassen werden , würde das Folgende funktionieren:df = df.xs('b', axis=1, level=1, drop_level=True)
Tiffany G. Wilson
27

Ab Pandas 0.24.0 können wir jetzt DataFrame.droplevel () verwenden :

cols = pd.MultiIndex.from_tuples([("a", "b"), ("a", "c")])
df = pd.DataFrame([[1,2], [3,4]], columns=cols)

df.droplevel(0, axis=1) 

#   b  c
#0  1  2
#1  3  4

Dies ist sehr nützlich, wenn Sie Ihre DataFrame-Methodenkette am Laufen halten möchten.

jxc
quelle
Dies ist die "reinste" Lösung, da ein neuer DataFrame zurückgegeben wird, anstatt ihn "an Ort und Stelle" ändern zu lassen.
EliadL
16

Sie können dies auch erreichen, indem Sie die Spalten umbenennen:

df.columns = ['a', 'b']

Dies beinhaltet einen manuellen Schritt, kann jedoch eine Option sein, insbesondere wenn Sie Ihren Datenrahmen eventuell umbenennen würden.

sedeh
quelle
Dies ist im Wesentlichen die erste Antwort von Mint. Jetzt müssen Sie auch nicht mehr die Liste der Namen angeben (was im Allgemeinen mühsam ist), wie sie Ihnen von gegeben wird df.columns.get_level_values(1).
Eric O Lebigot
12

Ein kleiner Trick sum mit Level = 1 (Arbeit, wenn Level = 1 eindeutig ist)

df.sum(level=1,axis=1)
Out[202]: 
   b  c
0  1  2
1  3  4

Häufigere Lösung get_level_values

df.columns=df.columns.get_level_values(1)
df
Out[206]: 
   b  c
0  1  2
1  3  4
YOBEN_S
quelle
4

Ich habe mit diesem Problem zu kämpfen, da ich nicht weiß, warum meine droplevel () -Funktion nicht funktioniert. Arbeiten Sie mehrere durch und lernen Sie, dass 'a' in Ihrer Tabelle der Spaltenname und 'b', 'c' der Index ist. Tun Sie dies wird helfen

df.columns.name = None
df.reset_index() #make index become label
dhFrank
quelle
1
Dies gibt die gewünschte Ausgabe überhaupt nicht wieder.
Eric O Lebigot
Basierend auf dem Datum, an dem dies veröffentlicht wurde, war die Drop-Stufe möglicherweise nicht in Ihrer Version von Pandas enthalten (sie wurde der stabilen Version 24.0 im Januar 2019 hinzugefügt)
LinkBerest