Auswählen von Spalten aus Pandas MultiIndex

Lesezeit: 8 Minuten

Auswahlen von Spalten aus Pandas
metakermit

Ich habe DataFrame mit MultiIndex-Spalten, die wie folgt aussehen:

# sample data
col = pd.MultiIndex.from_arrays([['one', 'one', 'one', 'two', 'two', 'two'],
                                ['a', 'b', 'c', 'a', 'b', 'c']])
data = pd.DataFrame(np.random.randn(4, 6), columns=col)
data

Beispieldaten

Was ist die richtige und einfache Methode, um nur bestimmte Spalten auszuwählen (z. B. ['a', 'c'], kein Bereich) aus der zweiten Ebene?

Aktuell mache ich es so:

import itertools
tuples = [i for i in itertools.product(['one', 'two'], ['a', 'c'])]
new_index = pd.MultiIndex.from_tuples(tuples)
print(new_index)
data.reindex_axis(new_index, axis=1)

erwartetes Ergebnis

Es fühlt sich jedoch nicht nach einer guten Lösung an, da ich aussteigen muss itertools, einen weiteren MultiIndex von Hand erstellen und dann neu indizieren (und mein eigentlicher Code ist noch unordentlicher, da die Spaltenlisten nicht so einfach zu holen sind). Ich bin mir ziemlich sicher, dass es welche geben müssen ix oder xs Methode, dies zu tun, aber alles, was ich versucht habe, führte zu Fehlern.

  • Haben Sie versucht, Wörterbücher zu verwenden?

    – darmat

    27. August ’13 um 16:01

  • Nicht, habe ich nicht. Sie wollen den MultiIndex schneller aufbauen? Wenn ja, ist das nicht der Punkt – ich möchte es vermeiden und direkt mit so etwas indizieren wie data.xs(['a', 'c'], axis=1, level=1)

    – metakermit

    27. August ’13 um 16:04

  • Gibt es einen Grund, warum Sie diese Ebene als zweite und nicht als erste Ebene haben?

    – BrenBarn

    27. August ’13 um 16:06

  • Es ist für mich visuell intuitiver für die Art von Daten, die ich habe. Außerdem wollte ich lernen, wie man es allgemein macht – für ein beliebiges Niveau.

    – metakermit

    28. August ’13 um 9:39

  • In späteren Versionen von Pandas können Sie loc zusammen mit pd.IndexSlice API, die jetzt die bevorzugte Methode zum Schneiden von MultIndexen ist. Siehe diese Antwort und diesen Beitrag.

    – cs95

    23. Januar ’19 um 23:03

Auswahlen von Spalten aus Pandas
Guilherme Salome

Der einfachste Weg ist mit .loc:

>>> data.loc[:, (['one', 'two'], ['a', 'b'])]


   one       two     
     a    b    a    b
0  0.4 -0.6 -0.7  0.9
1  0.1  0.4  0.5 -0.3
2  0.7 -1.6  0.7 -0.8
3 -0.9  2.6  1.9  0.6

Erinnere dich daran [] und () haben besondere Bedeutung im Umgang mit a MultiIndex Objekt:

(…) ein Tupel wird als eins interpretiert mehrstufig Schlüssel

(…) eine Liste wird verwendet, um mehrere Schlüssel anzugeben [on the same level]

(…) ein Tupel von Listen bezieht sich auf mehrere Werte innerhalb einer Ebene

Wenn wir schreiben (['one', 'two'], ['a', 'b']), die erste Liste innerhalb des Tupels gibt alle Werte an, die wir aus der 1. MultiIndex. Die zweite Liste innerhalb des Tupels gibt alle Werte an, die wir aus der 2. Ebene des wollen MultiIndex.

Bearbeiten 1: Eine andere Möglichkeit ist die Verwendung slice(None) um anzugeben, dass wir alles aus der ersten Ebene wollen (funktioniert ähnlich wie das Schneiden mit : in Listen). Und dann geben Sie an, welche Spalten aus der zweiten Ebene wir wollen.

>>> data.loc[:, (slice(None), ["a", "b"])]

   one       two     
     a    b    a    b
0  0.4 -0.6 -0.7  0.9
1  0.1  0.4  0.5 -0.3
2  0.7 -1.6  0.7 -0.8
3 -0.9  2.6  1.9  0.6

Wenn die Syntax slice(None) dich anspricht, dann ist eine andere Möglichkeit zu verwenden pd.IndexSlice, die das Slicing von Frames mit aufwändigeren Indizes unterstützt.

>>> data.loc[:, pd.IndexSlice[:, ["a", "b"]]]

   one       two     
     a    b    a    b
0  0.4 -0.6 -0.7  0.9
1  0.1  0.4  0.5 -0.3
2  0.7 -1.6  0.7 -0.8
3 -0.9  2.6  1.9  0.6

Beim Benutzen pd.IndexSlice, wir können benutzen : wie üblich, um den Rahmen zu schneiden.

Quelle: MultiIndex / Erweiterte Indexierung, Wie benutzt man slice(None)

  • Beachten Sie, dass der Spaltenname des resultierenden DataFrame ist a b a b und nicht a c a c.

    – Silvan Mühlemann

    14. Januar ’20 um 19:09

  • @SilvanMühlemann Habe ich behoben, bitte schau mal nach und lass mich wissen, wenn es noch andere Probleme gibt! Danke fürs Helfen.

    – Guilherme Salome

    14. Januar ’20 um 21:45

  • Dies ist der intuitivste Weg.

    – Arnab Biswas

    6. September ’21 um 10:46

1641811025 724 Auswahlen von Spalten aus Pandas
DSM

Es ist nicht so toll, aber vielleicht:

>>> data
        one                           two                    
          a         b         c         a         b         c
0 -0.927134 -1.204302  0.711426  0.854065 -0.608661  1.140052
1 -0.690745  0.517359 -0.631856  0.178464 -0.312543 -0.418541
2  1.086432  0.194193  0.808235 -0.418109  1.055057  1.886883
3 -0.373822 -0.012812  1.329105  1.774723 -2.229428 -0.617690
>>> data.loc[:,data.columns.get_level_values(1).isin({"a", "c"})]
        one                 two          
          a         c         a         c
0 -0.927134  0.711426  0.854065  1.140052
1 -0.690745 -0.631856  0.178464 -0.418541
2  1.086432  0.808235 -0.418109  1.886883
3 -0.373822  1.329105  1.774723 -0.617690

würde funktionieren?

  • Tatsächlich denke ich, dass dies der optimale Weg ist, um eine Liste von Labels in einer beliebigen MultiIndex-Ebene herauszufiltern, ohne alle Tupel zu erstellen. ich würde es einfach benutzen loc zur Klarheit.

    – Viktor Kerkez

    27. August ’13 um 16:55


  • Um die Reihenfolge der Spalten beizubehalten, verwenden Sie besser isin(["a", "b"]).

    – Friedlich

    14. Apr. ’17 um 14:39

  • @Friedlich: Was? Das ändert nichts. Das Ergebnis des isin-Aufrufs ist eine boolsche Reihe, und ihre Reihenfolge wird durch die Reihenfolge der ursprünglichen Reihe bestimmt, nicht durch das Argument für isin.

    – DSM

    14. Apr. ’17 um 14:46

  • Ich versuchte es. Und weil {"a", "b"} ist ein Wörterbuch, es gab mir Spalten, die als geordnet sind {"b", "a"}. Natürlich hatte ich andere Spaltennamen. Was ist los?

    – Friedlich

    14. Apr. ’17 um 14:52

  • {"a", "b"} ist ein Set, kein Wörterbuch, und das hat nichts mit der Funktionsweise von isin zu tun. Wenn Sie eine Frage zum Verhalten von Pandas haben, öffnen Sie bitte eine neue Frage, anstatt eine vier Jahre alte Antwort zu kommentieren.

    – DSM

    14. Apr. ’17 um 14:54

Sie können entweder loc oder ix Ich zeige ein Beispiel mit loc:

data.loc[:, [('one', 'a'), ('one', 'c'), ('two', 'a'), ('two', 'c')]]

Wenn Sie einen Multiindexed DataFrame haben und nur einige der Spalten herausfiltern möchten, müssen Sie eine Liste von Tupeln übergeben, die diesen Spalten entsprechen. Der itertools-Ansatz war also ziemlich in Ordnung, aber Sie müssen keinen neuen MultiIndex erstellen:

data.loc[:, list(itertools.product(['one', 'two'], ['a', 'c']))]

  • Und selbst .loc und ähnliches sind nicht erforderlich. data[[('one', 'a'), ('one', 'c'), ('two', 'a'), ('two', 'c')]] funktioniert auch. Getestet am 0.23.4.

    – Anton Tarasenko

    21. März ’19 um 17:09

Ich denke, es gibt (jetzt) ​​einen viel besseren Weg, weshalb ich mir die Mühe mache, diese Frage (die das beste Google-Ergebnis war) aus dem Schatten zu ziehen:

data.select(lambda x: x[1] in ['a', 'b'], axis=1)

liefert Ihre erwartete Ausgabe in einem schnellen und sauberen Einzeiler:

        one                 two          
          a         b         a         b
0 -0.341326  0.374504  0.534559  0.429019
1  0.272518  0.116542 -0.085850 -0.330562
2  1.982431 -0.420668 -0.444052  1.049747
3  0.162984 -0.898307  1.762208 -0.101360

Es ist meist selbsterklärend, die [1] bezieht sich auf das Niveau.

1641811025 108 Auswahlen von Spalten aus Pandas
cs95

ix und select sind veraltet!

Die Verwendung von pd.IndexSlice macht loc eine vorzuziehende Option zu ix und select.


DataFrame.loc mit pd.IndexSlice

# Setup
col = pd.MultiIndex.from_arrays([['one', 'one', 'one', 'two', 'two', 'two'],
                                ['a', 'b', 'c', 'a', 'b', 'c']])
data = pd.DataFrame('x', index=range(4), columns=col)
data

  one       two      
    a  b  c   a  b  c
0   x  x  x   x  x  x
1   x  x  x   x  x  x
2   x  x  x   x  x  x
3   x  x  x   x  x  x

data.loc[:, pd.IndexSlice[:, ['a', 'c']]]

  one    two   
    a  c   a  c
0   x  x   x  x
1   x  x   x  x
2   x  x   x  x
3   x  x   x  x

Sie können alternativ eine axis Parameter zu loc um deutlich zu machen, von welcher Achse aus Sie indizieren:

data.loc(axis=1)[pd.IndexSlice[:, ['a', 'c']]]

  one    two   
    a  c   a  c
0   x  x   x  x
1   x  x   x  x
2   x  x   x  x
3   x  x   x  x

MultiIndex.get_level_values

Berufung data.columns.get_level_values filtern mit loc ist eine andere Möglichkeit:

data.loc[:, data.columns.get_level_values(1).isin(['a', 'c'])]

  one    two   
    a  c   a  c
0   x  x   x  x
1   x  x   x  x
2   x  x   x  x
3   x  x   x  x

Dies kann natürlich das Filtern nach jedem bedingten Ausdruck auf einer einzigen Ebene ermöglichen. Hier ist ein zufälliges Beispiel mit lexikografischer Filterung:

data.loc[:, data.columns.get_level_values(1) > 'b']

  one two
    c   c
0   x   x
1   x   x
2   x   x
3   x   x

Weitere Informationen zum Slicing und Filtern von MultiIndexes finden Sie unter Select rows in pandas MultiIndex DataFrame.

  • Beide Ansätze funktionieren für mich, aber letzteres scheint schneller zu sein. Ich habe beobachtet pd.IndexSlice dreimal so lang (zumindest bei meinem Datensatz, der einen zweistufigen Spalten-Multiindex und die Form hat) (3610, 30)). –> pd.IndexSlice mit 670 µs ± 4.49 µs per loop und data.loc[:, data.columns.get_level_values(1).isin(['a', 'b', 'c'])] mit 215 µs ± 3.05 µs per loop

    – Pascal

    15. November ’21 um 8:20


  • Auch: pd.IndexSlice behält die Reihenfolge der Spalten in meinem Fall nicht bei (pandas==1.2.4), die zweite tut es.

    – Pascal

    15. November ’21 um 8:28


  • Guter Hinweis, danke.

    – cs95

    19. November ’21 um 9:42

1641811025 67 Auswahlen von Spalten aus Pandas
Marc P.

Um alle benannten Spalten auszuwählen 'a' und 'c' Auf der zweiten Ebene Ihres Spaltenindexers können Sie Slicer verwenden:

>>> data.loc[:, (slice(None), ('a', 'c'))]

        one                 two          
          a         c         a         c
0 -0.983172 -2.495022 -0.967064  0.124740
1  0.282661 -0.729463 -0.864767  1.716009
2  0.942445  1.276769 -0.595756 -0.973924
3  2.182908 -0.267660  0.281916 -0.587835

Hier Sie können mehr über Slicer lesen.

  • Beide Ansätze funktionieren für mich, aber letzteres scheint schneller zu sein. Ich habe beobachtet pd.IndexSlice dreimal so lang (zumindest bei meinem Datensatz, der einen zweistufigen Spalten-Multiindex und die Form hat) (3610, 30)). –> pd.IndexSlice mit 670 µs ± 4.49 µs per loop und data.loc[:, data.columns.get_level_values(1).isin(['a', 'b', 'c'])] mit 215 µs ± 3.05 µs per loop

    – Pascal

    15. November ’21 um 8:20


  • Auch: pd.IndexSlice behält die Reihenfolge der Spalten in meinem Fall nicht bei (pandas==1.2.4), die zweite tut es.

    – Pascal

    15. November ’21 um 8:28


  • Guter Hinweis, danke.

    – cs95

    19. November ’21 um 9:42

1641811025 353 Auswahlen von Spalten aus Pandas
Nick P

Ein meiner Meinung nach etwas einfacheres Riff auf Marc Ps Antwort mit Slice:

import pandas as pd
col = pd.MultiIndex.from_arrays([['one', 'one', 'one', 'two', 'two', 'two'], ['a', 'b', 'c', 'a', 'b', 'c']])
data = pd.DataFrame(np.random.randn(4, 6), columns=col)

data.loc[:, pd.IndexSlice[:, ['a', 'c']]]

        one                 two          
          a         c         a         c
0 -1.731008  0.718260 -1.088025 -1.489936
1 -0.681189  1.055909  1.825839  0.149438
2 -1.674623  0.769062  1.857317  0.756074
3  0.408313  1.291998  0.833145 -0.471879

Ab Pandas 0.21 oder so, .select wird zugunsten von .loc . eingestellt.

.

294670cookie-checkAuswählen von Spalten aus Pandas MultiIndex

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy