Mehrdeutigkeit in der Definition der Pandas Dataframe / Numpy Array-Achse


89

Ich war sehr verwirrt darüber, wie Python-Achsen definiert sind und ob sie sich auf die Zeilen oder Spalten eines DataFrames beziehen. Betrachten Sie den folgenden Code:

>>> df = pd.DataFrame([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]], columns=["col1", "col2", "col3", "col4"])
>>> df
   col1  col2  col3  col4
0     1     1     1     1
1     2     2     2     2
2     3     3     3     3

Wenn wir also anrufen df.mean(axis=1), erhalten wir einen Mittelwert über die Zeilen:

>>> df.mean(axis=1)
0    1
1    2
2    3

Wenn wir jedoch aufrufen df.drop(name, axis=1), löschen wir tatsächlich eine Spalte , keine Zeile:

>>> df.drop("col4", axis=1)
   col1  col2  col3
0     1     1     1
1     2     2     2
2     3     3     3

Kann mir jemand helfen zu verstehen, was unter einer "Achse" in pandas / numpy / scipy zu verstehen ist?

Eine Randnotiz DataFrame.meankönnte einfach falsch definiert sein. In der Dokumentation heißt es, DataFrame.meandass axis=1dies einen Mittelwert über die Spalten bedeuten soll, nicht über die Zeilen ...


Eine ausführliche Erläuterung der Aliase, 'Spalten' und 'Index' / 'Zeilen' finden Sie in dieser Antwort unten .
Ted Petrou

Das ist einfach komisch. Die Achse sollte über die meanund die konsistent sein drop. Es bedarf nichtlinearen Denkens, um zum tatsächlichen Verhalten zu gelangen.
Javadba

Antworten:


162

Es ist vielleicht am einfachsten, sich daran zu erinnern, dass 0 = unten und 1 = quer .

Das heisst:

  • Verwenden Sie axis=0diese Option , um eine Methode in jeder Spalte oder auf die Zeilenbeschriftungen (den Index) anzuwenden.
  • Verwenden Sie axis=1diese Option , um eine Methode auf jede Zeile oder auf die Spaltenbeschriftungen anzuwenden.

Hier ist ein Bild, das die Teile eines DataFrames zeigt, auf die sich jede Achse bezieht:

Es ist auch nützlich, sich daran zu erinnern, dass Pandas NumPys Gebrauch des Wortes folgt axis. Die Verwendung wird im NumPy- Glossar erläutert :

Achsen werden für Arrays mit mehr als einer Dimension definiert. Ein zweidimensionales Array hat zwei entsprechende Achsen: Die erste verläuft vertikal nach unten über Zeilen (Achse 0) und die zweite horizontal über Spalten (Achse 1) . [ meine Betonung ]

In Bezug auf die Methode in der Frage df.mean(axis=1)scheint also richtig definiert zu sein. Es wird der Mittelwert der Einträge horizontal über Spalten , dh entlang jeder einzelnen Zeile, berechnet. Andererseits df.mean(axis=0)wäre dies eine Operation, die vertikal nach unten über Reihen hinweg wirkt .

df.drop(name, axis=1)Bezieht sich in ähnlicher Weise auf eine Aktion für Spaltenbeschriftungen, da diese intuitiv über die horizontale Achse verlaufen. Wenn Sie angeben axis=0, wird die Methode stattdessen auf Zeilen angewendet .


2
Was mich zum Kampf brachte, war, dass df.apply (..., axis = 0) nicht über Achse 0 (den Index) "lief", sondern über die Spalten lief und die Serie mit allen Indizes zurückzog. Der Hinweis ist, dass df.apply (..., axis = 0) Series zurückgibt, sodass SIE eine Operation anwenden können, die über den gesamten Index läuft.
Moritzschaefer

1
Ich denke, es hilft auch, wenn Sie df.applyeine Methode wie ähnlich sehen df.sum. df.sum(axis=0)Summiert beispielsweise jede Spalte des DataFrame. Ebenso können Sie schreiben df.apply(sum, axis=0), um genau den gleichen Vorgang auszuführen. Während die Operation tatsächlich auf jede Spalte im DataFrame angewendet wird, läuft die eigentliche Funktion entlang der Achse 0.
Alex Riley

Es ist bedauerlich, dass die Namens- und Ordnungskonventionen das Gegenteil der R- Apply-Funktion sind - in R entspricht der niedrigere MARGIN(ähnlich wie axisin Pandas) Wert von "1" "Zeilen", was bedeutet, dass die Funktion auf jede Zeile angewendet wird , während die Ein größerer Wert von "2" bezieht sich auf "Spalten", was bedeutet, dass die Funktion auf jede Spalte angewendet wird .
Keith Hughitt

Es ist ein zerstörerischer Fehler in Pandas
Calculus

10

Ein anderer Weg zu erklären:

// Not realistic but ideal for understanding the axis parameter 
df = pd.DataFrame([[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3]],
                  columns=["idx1", "idx2", "idx3", "idx4"],
                  index=["idx1", "idx2", "idx3"]
                 )

---------------------------------------1
|          idx1  idx2  idx3  idx4
|    idx1     1     1     1     1
|    idx2     2     2     2     2
|    idx3     3     3     3     3
0

Über df.drop(Achse bedeutet die Position)

A: I wanna remove idx3.
B: **Which one**? // typing while waiting response: df.drop("idx3",
A: The one which is on axis 1
B: OK then it is >> df.drop("idx3", axis=1)

// Result
---------------------------------------1
|          idx1  idx2     idx4
|    idx1     1     1     1
|    idx2     2     2     2
|    idx3     3     3     3
0

Über df.apply(Achse bedeutet Richtung)

A: I wanna apply sum.
B: Which direction? // typing while waiting response: df.apply(lambda x: x.sum(),
A: The one which is on *parallel to axis 0*
B: OK then it is >> df.apply(lambda x: x.sum(), axis=0)

// Result
idx1    6
idx2    6
idx3    6
idx4    6

Denken Sie nicht, auf Achse 1 und parallel zu Achse 0 dasselbe zu bedeuten?
Nuance

9

Es gibt bereits richtige Antworten, aber ich gebe Ihnen ein anderes Beispiel mit> 2 Dimensionen.

Der Parameter axisbedeutet, dass die Achse geändert werden muss .
Angenommen, es gibt einen Datenrahmen mit der Dimension axbxc .

  • df.mean(axis=1)Gibt einen Datenrahmen mit der Abmessungsachse 1 xc zurück .
  • df.drop("col4", axis=1)Gibt einen Datenrahmen mit der Dimension ax (b-1) xc zurück .

Bedeutet hier axis=1die zweite Achse b, also wird der bWert in diesen Beispielen geändert.


1
Diese Antwort ist für mich intuitiver als jede Visualisierung, die ich zu diesem Thema gesehen habe. Xarray ist jedoch besser für mehrdimensionale Arrays als Pandas.
Alys

2

Es sollte allgemein bekannt sein, dass die Zeichenfolgenaliasnamen 'index' und 'column' anstelle der Ganzzahlen 0/1 verwendet werden können. Die Aliase sind viel expliziter und helfen mir, mich daran zu erinnern, wie die Berechnungen stattfinden. Ein weiterer Alias ​​für 'Index' ist 'Zeilen' .

Wenn axis='index'es verwendet wird, finden die Berechnungen in den Spalten statt, was verwirrend ist. Aber ich erinnere mich, dass ich ein Ergebnis erhalten habe, das die gleiche Größe wie eine andere Zeile hat.

Lassen Sie uns einige Daten auf dem Bildschirm anzeigen, um zu sehen, wovon ich spreche:

df = pd.DataFrame(np.random.rand(10, 4), columns=list('abcd'))
          a         b         c         d
0  0.990730  0.567822  0.318174  0.122410
1  0.144962  0.718574  0.580569  0.582278
2  0.477151  0.907692  0.186276  0.342724
3  0.561043  0.122771  0.206819  0.904330
4  0.427413  0.186807  0.870504  0.878632
5  0.795392  0.658958  0.666026  0.262191
6  0.831404  0.011082  0.299811  0.906880
7  0.749729  0.564900  0.181627  0.211961
8  0.528308  0.394107  0.734904  0.961356
9  0.120508  0.656848  0.055749  0.290897

Wenn wir den Mittelwert aller Spalten nehmen wollen, erhalten wir axis='index'Folgendes:

df.mean(axis='index')
a    0.562664
b    0.478956
c    0.410046
d    0.546366
dtype: float64

Das gleiche Ergebnis würde erzielt werden durch:

df.mean() # default is axis=0
df.mean(axis=0)
df.mean(axis='rows')

Verwenden Sie axis = 'column', um eine Operation von links nach rechts für die Zeilen zu verwenden. Ich erinnere mich daran, indem ich dachte, dass meinem DataFrame eine zusätzliche Spalte hinzugefügt werden könnte:

df.mean(axis='columns')
0    0.499784
1    0.506596
2    0.478461
3    0.448741
4    0.590839
5    0.595642
6    0.512294
7    0.427054
8    0.654669
9    0.281000
dtype: float64

Das gleiche Ergebnis würde erzielt werden durch:

df.mean(axis=1)

Fügen Sie eine neue Zeile mit Achse = 0 / Index / Zeilen hinzu

Verwenden Sie diese Ergebnisse, um zusätzliche Zeilen oder Spalten hinzuzufügen, um die Erklärung zu vervollständigen. Wenn Sie also axis = 0 / index / rows verwenden, erhalten Sie eine neue Zeile des DataFrame. Fügen wir eine Zeile hinzu:

df.append(df.mean(axis='rows'), ignore_index=True)

           a         b         c         d
0   0.990730  0.567822  0.318174  0.122410
1   0.144962  0.718574  0.580569  0.582278
2   0.477151  0.907692  0.186276  0.342724
3   0.561043  0.122771  0.206819  0.904330
4   0.427413  0.186807  0.870504  0.878632
5   0.795392  0.658958  0.666026  0.262191
6   0.831404  0.011082  0.299811  0.906880
7   0.749729  0.564900  0.181627  0.211961
8   0.528308  0.394107  0.734904  0.961356
9   0.120508  0.656848  0.055749  0.290897
10  0.562664  0.478956  0.410046  0.546366

Fügen Sie eine neue Spalte mit Achse = 1 / Spalten hinzu

Wenn Achse = 1 / Spalten ist, werden Daten erstellt, die leicht in eine eigene Spalte umgewandelt werden können:

df.assign(e=df.mean(axis='columns'))

          a         b         c         d         e
0  0.990730  0.567822  0.318174  0.122410  0.499784
1  0.144962  0.718574  0.580569  0.582278  0.506596
2  0.477151  0.907692  0.186276  0.342724  0.478461
3  0.561043  0.122771  0.206819  0.904330  0.448741
4  0.427413  0.186807  0.870504  0.878632  0.590839
5  0.795392  0.658958  0.666026  0.262191  0.595642
6  0.831404  0.011082  0.299811  0.906880  0.512294
7  0.749729  0.564900  0.181627  0.211961  0.427054
8  0.528308  0.394107  0.734904  0.961356  0.654669
9  0.120508  0.656848  0.055749  0.290897  0.281000

Es scheint, dass Sie alle Aliase mit den folgenden privaten Variablen sehen können:

df._AXIS_ALIASES
{'rows': 0}

df._AXIS_NUMBERS
{'columns': 1, 'index': 0}

df._AXIS_NAMES
{0: 'index', 1: 'columns'}

1

Wenn Achse = 'Zeilen' oder Achse = 0 ist, bedeutet dies, dass auf Elemente in Richtung der Zeilen von oben nach unten zugegriffen wird. Wenn Sie die Summe entlang der Achse = 0 anwenden, erhalten Sie Summen für jede Spalte.

Wenn Achse = 'Spalten' oder Achse = 1 ist, bedeutet dies, dass von links nach rechts auf Elemente in Richtung der Spalten zugegriffen wird. Wenn Sie die Summe entlang der Achse = 1 anwenden, erhalten Sie Summen für jede Zeile.

Immer noch verwirrend! Aber das oben Genannte macht es mir ein bisschen leichter.

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.