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
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)
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
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.
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
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:
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:
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.
cs95
ix und select sind veraltet!
Die Verwendung von pd.IndexSlice macht loc eine vorzuziehende Option zu ix und select.
# 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
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
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
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
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
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 mitpd.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