Wofür sind die Argumente 'Ebenen', 'Schlüssel' und Namen in der Concat-Funktion von Pandas?

93

Fragen

  • Wie benutze ich pd.concat?
  • Was ist der levels Argument?
  • Was ist der keys Argument?
  • Gibt es eine Reihe von Beispielen, die erklären, wie alle Argumente verwendet werden?

Die concatFunktion der Pandas ist das Schweizer Taschenmesser der sich verschmelzenden Versorgungsunternehmen. Die Vielfalt der Situationen, in denen es nützlich ist, ist zahlreich. In der vorhandenen Dokumentation werden einige Details zu einigen der optionalen Argumente ausgelassen. Unter ihnen sind dielevels und keysArgumente. Ich machte mich daran herauszufinden, was diese Argumente bewirken.

Ich werde eine Frage stellen, die als Tor zu vielen Aspekten von dient pd.concat.

Betrachten Sie den Datenrahmen d1, d2und d3:

import pandas as pd

d1 = pd.DataFrame(dict(A=.1, B=.2, C=.3), [2, 3])
d2 = pd.DataFrame(dict(B=.4, C=.5, D=.6), [1, 2])
d3 = pd.DataFrame(dict(A=.7, B=.8, D=.9), [1, 3])

Wenn ich diese zusammen mit verketten würde

pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'])

Ich erhalte das erwartete Ergebnis mit einem pandas.MultiIndexfür mein columnsObjekt:

        A    B    C    D
d1 2  0.1  0.2  0.3  NaN
   3  0.1  0.2  0.3  NaN
d2 1  NaN  0.4  0.5  0.6
   2  NaN  0.4  0.5  0.6
d3 1  0.7  0.8  NaN  0.9
   3  0.7  0.8  NaN  0.9

Ich wollte jedoch die levelsArgumentdokumentation verwenden :

Ebenen : Liste der Sequenzen, Standard Keine. Bestimmte Ebenen (eindeutige Werte), die zum Erstellen eines MultiIndex verwendet werden sollen. Andernfalls werden sie aus den Schlüsseln abgeleitet.

Also habe ich bestanden

pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2']])

Und hol dir einen KeyError

ValueError: Key d3 not in level Index(['d1', 'd2'], dtype='object')

Das machte Sinn. Die von mir bestandenen Stufen waren nicht ausreichend, um die durch die Tasten angegebenen erforderlichen Stufen zu beschreiben. Hätte ich wie oben nichts bestanden, werden die Werte abgeleitet (wie in der Dokumentation angegeben). Aber wie kann ich dieses Argument sonst besser nutzen?

Wenn ich das stattdessen versuchen würde:

pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2', 'd3']])

Ich und habe die gleichen Ergebnisse wie oben. Aber wenn ich den Levels noch einen Wert hinzufüge,

df = pd.concat([d1, d2, d3], keys=['d1', 'd2', 'd3'], levels=[['d1', 'd2', 'd3', 'd4']])

Am Ende habe ich den gleichen Datenrahmen, aber das Ergebnis MultiIndexhat einen unbenutzten Pegel.

df.index.levels[0]

Index(['d1', 'd2', 'd3', 'd4'], dtype='object')

Also, was ist der Sinn des levelArguments und sollte ich verwendenkeys ?

Ich benutze Python 3.6 und Pandas 0.22.

piRSquared
quelle

Antworten:

122

Während ich diese Frage für mich selbst beantwortete, lernte ich viele Dinge und wollte einen Katalog mit Beispielen und Erklärungen zusammenstellen.

Die konkrete Antwort auf den Punkt der levels Arguments wird gegen Ende kommen.

pandas.concat: Das fehlende Handbuch

Link zur aktuellen Dokumentation

Importiert und definiert Objekte

import pandas as pd

d1 = pd.DataFrame(dict(A=.1, B=.2, C=.3), index=[2, 3])
d2 = pd.DataFrame(dict(B=.4, C=.5, D=.6), index=[1, 2])
d3 = pd.DataFrame(dict(A=.7, B=.8, D=.9), index=[1, 3])

s1 = pd.Series([1, 2], index=[2, 3])
s2 = pd.Series([3, 4], index=[1, 2])
s3 = pd.Series([5, 6], index=[1, 3])

Argumente

objs

Das erste Argument, auf das wir stoßen, ist objs:

objs : eine Sequenz oder Zuordnung von Serien-, DataFrame- oder Panel-Objekten Wenn ein Diktat übergeben wird, werden die sortierten Schlüssel als Schlüsselargument verwendet, sofern sie nicht übergeben werden. In diesem Fall werden die Werte ausgewählt (siehe unten). Alle None-Objekte werden stillschweigend gelöscht, es sei denn, sie sind alle None. In diesem Fall wird ein ValueError ausgelöst

  • Wir sehen dies normalerweise bei einer Liste von Seriesoder DataFrameObjekten.
  • Ich werde zeigen, dass dictdas auch sehr nützlich sein kann.
  • Generatoren können ebenfalls verwendet werden und können nützlich sein, wenn sie mapwie in verwendet werdenmap(f, list_of_df)

Vorerst werden wir mit einer Liste von einigen der Stick DataFrameund SeriesObjekte oben definiert sind . Ich werde später zeigen, wie Wörterbücher genutzt werden können, um sehr nützliche MultiIndexErgebnisse zu erzielen.

pd.concat([d1, d2])

     A    B    C    D
2  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6

axis

Das zweite Argument ist das axisStandardwert 0:

Achse : {0 / 'Index', 1 / 'Spalten'}, Standard 0 Die Achse, entlang der verkettet werden soll.

Zwei DataFrames mit axis=0(gestapelt)

Für Werte von 0oder wollen indexwir sagen: "Entlang der Spalten ausrichten und zum Index hinzufügen".

Wie oben gezeigt, wo wir verwendet haben axis=0, weil dies 0der Standardwert ist und wir sehen, dass der Index von d2den Index von erweitert, d1obwohl es eine Überlappung des Werts gibt 2:

pd.concat([d1, d2], axis=0)

     A    B    C    D
2  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6

Zwei DataFrames mit axis=1(nebeneinander)

Für Werte 1oder columnswir wollen sagen: "Am Index ausrichten und zu den Spalten hinzufügen",

pd.concat([d1, d2], axis=1)

     A    B    C    B    C    D
1  NaN  NaN  NaN  0.4  0.5  0.6
2  0.1  0.2  0.3  0.4  0.5  0.6
3  0.1  0.2  0.3  NaN  NaN  NaN

Wir können sehen, dass der resultierende Index die Vereinigung von Indizes ist und die resultierenden Spalten die Erweiterung von Spalten d1um die Spalten von sind d2.

Zwei (oder drei) Seriesmit axis=0(gestapelt)

Bei der Kombination pandas.Serieszusammen axis=0, erhalten wir ein zurück pandas.Series. Der Name des Ergebnisses Serieslautet, Nonesofern nicht alle Serieszusammen den gleichen Namen haben. Achten Sie darauf, 'Name: A'wann wir das Ergebnis ausdrucken Series. Wenn es nicht vorhanden ist, können wir annehmen, dass der SeriesName ist None.

               |                       |                        |  pd.concat(
               |  pd.concat(           |  pd.concat(            |      [s1.rename('A'),
 pd.concat(    |      [s1.rename('A'), |      [s1.rename('A'),  |       s2.rename('B'),
     [s1, s2]) |       s2])            |       s2.rename('A')]) |       s3.rename('A')])
-------------- | --------------------- | ---------------------- | ----------------------
2    1         | 2    1                | 2    1                 | 2    1
3    2         | 3    2                | 3    2                 | 3    2
1    3         | 1    3                | 1    3                 | 1    3
2    4         | 2    4                | 2    4                 | 2    4
dtype: int64   | dtype: int64          | Name: A, dtype: int64  | 1    5
               |                       |                        | 3    6
               |                       |                        | dtype: int64

Zwei (oder drei) Seriesmit axis=1(nebeneinander)

Bei der Kombination von pandas.Serieszusammen axis=1, es ist das nameAttribut , das wir zu beziehen , um einen Spaltennamen in den resultierenden abzuleiten pandas.DataFrame.

                       |                       |  pd.concat(
                       |  pd.concat(           |      [s1.rename('X'),
 pd.concat(            |      [s1.rename('X'), |       s2.rename('Y'),
     [s1, s2], axis=1) |       s2], axis=1)    |       s3.rename('Z')], axis=1)
---------------------- | --------------------- | ------------------------------
     0    1            |      X    0           |      X    Y    Z
1  NaN  3.0            | 1  NaN  3.0           | 1  NaN  3.0  5.0
2  1.0  4.0            | 2  1.0  4.0           | 2  1.0  4.0  NaN
3  2.0  NaN            | 3  2.0  NaN           | 3  2.0  NaN  6.0

Gemischt Seriesund DataFramemit axis=0(gestapelt)

Wenn Sie eine Verkettung von a Seriesund DataFrameAlong durchführen axis=0, konvertieren wir alle Seriesin einzelne Spalten DataFrame.

Beachten Sie besonders, dass dies eine Verkettung ist axis=0. Das bedeutet, dass der Index (die Zeilen) erweitert wird, während die Spalten ausgerichtet werden. In den folgenden Beispielen sehen wir, dass der Index zu [2, 3, 2, 3]einem wahllosen Anhängen von Indizes wird. Die Spalten überlappen sich nur, wenn ich die Benennung der SeriesSpalte mit dem Argument erzwinge to_frame:

 pd.concat(               |
     [s1.to_frame(), d1]) |  pd.concat([s1, d1])
------------------------- | ---------------------
     0    A    B    C     |      0    A    B    C
2  1.0  NaN  NaN  NaN     | 2  1.0  NaN  NaN  NaN
3  2.0  NaN  NaN  NaN     | 3  2.0  NaN  NaN  NaN
2  NaN  0.1  0.2  0.3     | 2  NaN  0.1  0.2  0.3
3  NaN  0.1  0.2  0.3     | 3  NaN  0.1  0.2  0.3

Sie können sehen, dass die Ergebnisse von pd.concat([s1, d1])denen die gleichen sind, als ob ich die durchgeführt hätteto_frame selbst durchgeführt hätte.

Ich kann jedoch den Namen der resultierenden Spalte mit einem Parameter an steuern to_frame. Das Umbenennen von Seriesmit der renameMethode steuert nicht den Spaltennamen im Ergebnis DataFrame.

 # Effectively renames       |                            |
 # `s1` but does not align   |  # Does not rename.  So    |  # Renames to something
 # with columns in `d1`      |  # Pandas defaults to `0`  |  # that does align with `d1`
 pd.concat(                  |  pd.concat(                |  pd.concat(
     [s1.to_frame('X'), d1]) |      [s1.rename('X'), d1]) |      [s1.to_frame('B'), d1])
---------------------------- | -------------------------- | ----------------------------
     A    B    C    X        |      0    A    B    C      |      A    B    C
2  NaN  NaN  NaN  1.0        | 2  1.0  NaN  NaN  NaN      | 2  NaN  1.0  NaN
3  NaN  NaN  NaN  2.0        | 3  2.0  NaN  NaN  NaN      | 3  NaN  2.0  NaN
2  0.1  0.2  0.3  NaN        | 2  NaN  0.1  0.2  0.3      | 2  0.1  0.2  0.3
3  0.1  0.2  0.3  NaN        | 3  NaN  0.1  0.2  0.3      | 3  0.1  0.2  0.3

Gemischt Seriesund DataFramemit axis=1(nebeneinander)

Das ist ziemlich intuitiv. SeriesDer Spaltenname verwendet standardmäßig eine Aufzählung solcher SeriesObjekte, wenn ein nameAttribut nicht verfügbar ist.

                    |  pd.concat(
 pd.concat(         |      [s1.rename('X'),
     [s1, d1],      |       s2, s3, d1],
     axis=1)        |      axis=1)
------------------- | -------------------------------
   0    A    B    C |      X    0    1    A    B    C
2  1  0.1  0.2  0.3 | 1  NaN  3.0  5.0  NaN  NaN  NaN
3  2  0.1  0.2  0.3 | 2  1.0  4.0  NaN  0.1  0.2  0.3
                    | 3  2.0  NaN  6.0  0.1  0.2  0.3

join

Das dritte Argument joinbeschreibt, ob die resultierende Zusammenführung eine äußere Zusammenführung (Standard) oder eine innere Zusammenführung sein soll.

join : {'inner', 'äußere'}, Standard 'äußere'
Umgang mit Indizes auf anderen Achsen.

Es stellt sich heraus, es gibt keine leftoder rightOption alspd.concat mehr als nur zwei Objekte zum Zusammenführen verarbeitet werden können.

Im Fall von d1und sehen d2die Optionen folgendermaßen aus:

outer

pd.concat([d1, d2], axis=1, join='outer')

     A    B    C    B    C    D
1  NaN  NaN  NaN  0.4  0.5  0.6
2  0.1  0.2  0.3  0.4  0.5  0.6
3  0.1  0.2  0.3  NaN  NaN  NaN

inner

pd.concat([d1, d2], axis=1, join='inner')

     A    B    C    B    C    D
2  0.1  0.2  0.3  0.4  0.5  0.6

join_axes

Das vierte Argument ist das, was es uns ermöglicht, unsere leftVerschmelzung und mehr zu tun .

join_axes : Liste der Indexobjekte
Spezifische Indizes, die für die anderen n - 1 Achsen verwendet werden sollen, anstatt die innere / äußere Mengenlogik auszuführen .

Linke Zusammenführung

pd.concat([d1, d2, d3], axis=1, join_axes=[d1.index])

     A    B    C    B    C    D    A    B    D
2  0.1  0.2  0.3  0.4  0.5  0.6  NaN  NaN  NaN
3  0.1  0.2  0.3  NaN  NaN  NaN  0.7  0.8  0.9

Richtig zusammenführen

pd.concat([d1, d2, d3], axis=1, join_axes=[d3.index])

     A    B    C    B    C    D    A    B    D
1  NaN  NaN  NaN  0.4  0.5  0.6  0.7  0.8  0.9
3  0.1  0.2  0.3  NaN  NaN  NaN  0.7  0.8  0.9

ignore_index

ignore_index : boolean, default False
Wenn True, verwenden Sie die Indexwerte nicht entlang der Verkettungsachse. Die resultierende Achse wird mit 0, ..., n - 1 bezeichnet. Dies ist nützlich, wenn Sie Objekte verketten, bei denen die Verkettungsachse keine aussagekräftigen Indexinformationen enthält. Beachten Sie, dass die Indexwerte auf den anderen Achsen im Join weiterhin berücksichtigt werden.

Wie , wenn ich stapeln d1oben auf d2, wenn ich über die Indexwerte sich nicht, konnte ich sie zurücksetzen oder sie ignorieren.

                      |  pd.concat(             |  pd.concat(
                      |      [d1, d2],          |      [d1, d2]
 pd.concat([d1, d2])  |      ignore_index=True) |  ).reset_index(drop=True)
--------------------- | ----------------------- | -------------------------
     A    B    C    D |      A    B    C    D   |      A    B    C    D
2  0.1  0.2  0.3  NaN | 0  0.1  0.2  0.3  NaN   | 0  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN | 1  0.1  0.2  0.3  NaN   | 1  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6 | 2  NaN  0.4  0.5  0.6   | 2  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6 | 3  NaN  0.4  0.5  0.6   | 3  NaN  0.4  0.5  0.6

Und bei der Verwendung von axis=1:

                                   |     pd.concat(
                                   |         [d1, d2], axis=1,
 pd.concat([d1, d2], axis=1)       |         ignore_index=True)
-------------------------------    |    -------------------------------
     A    B    C    B    C    D    |         0    1    2    3    4    5
1  NaN  NaN  NaN  0.4  0.5  0.6    |    1  NaN  NaN  NaN  0.4  0.5  0.6
2  0.1  0.2  0.3  0.4  0.5  0.6    |    2  0.1  0.2  0.3  0.4  0.5  0.6
3  0.1  0.2  0.3  NaN  NaN  NaN    |    3  0.1  0.2  0.3  NaN  NaN  NaN

keys

Wir können eine Liste von Skalarwerten oder Tupeln übergeben, um dem entsprechenden MultiIndex Tupel- oder Skalarwerte zuzuweisen. Die Länge der übergebenen Liste muss mit der Anzahl der verketteten Elemente übereinstimmen.

Schlüssel : Sequenz, Standard Keine
Wenn mehrere Ebenen bestanden wurden, sollten Tupel enthalten. Erstellen Sie einen hierarchischen Index mit den übergebenen Schlüsseln als äußerste Ebene

axis=0

Beim Verketten von SeriesObjekten entlang axis=0(Erweitern des Index).

Diese Schlüssel werden zu einer neuen Anfangsebene eines MultiIndexObjekts im Indexattribut.

 #           length 3             length 3           #         length 2        length 2
 #          /--------\         /-----------\         #          /----\         /------\
 pd.concat([s1, s2, s3], keys=['A', 'B', 'C'])       pd.concat([s1, s2], keys=['A', 'B'])
----------------------------------------------      -------------------------------------
A  2    1                                           A  2    1
   3    2                                              3    2
B  1    3                                           B  1    3
   2    4                                              2    4
C  1    5                                           dtype: int64
   3    6
dtype: int64

Wir können jedoch mehr als skalare Werte im keysArgument verwenden, um eine noch tiefere zu erstellen MultiIndex. Hier übergeben wir tuplesder Länge 2 die vorangestellten zwei neuen Ebenen von a MultiIndex:

 pd.concat(
     [s1, s2, s3],
     keys=[('A', 'X'), ('A', 'Y'), ('B', 'X')])
-----------------------------------------------
A  X  2    1
      3    2
   Y  1    3
      2    4
B  X  1    5
      3    6
dtype: int64

axis=1

Es ist ein bisschen anders, wenn man sich entlang von Spalten erstreckt. Bei der Verwendung axis=0(siehe oben) keysfungierten unsere MultiIndexzusätzlich zum vorhandenen Index als Ebenen. Denn axis=1wir beziehen uns auf eine Achse, die SeriesObjekte nicht haben, nämlich das columnsAttribut.

Variationen von zwei Seriesmitaxis=1

Beachten Sie, dass die Benennung von s1und s2wichtig ist, solange keine übergeben keyswerden. Sie wird jedoch überschrieben, wenn sie übergeben keyswerden.

               |                       |                        |  pd.concat(
               |  pd.concat(           |  pd.concat(            |      [s1.rename('U'),
 pd.concat(    |      [s1, s2],        |      [s1.rename('U'),  |       s2.rename('V')],
     [s1, s2], |      axis=1,          |       s2.rename('V')], |       axis=1,
     axis=1)   |      keys=['X', 'Y']) |       axis=1)          |       keys=['X', 'Y'])
-------------- | --------------------- | ---------------------- | ----------------------
     0    1    |      X    Y           |      U    V            |      X    Y
1  NaN  3.0    | 1  NaN  3.0           | 1  NaN  3.0            | 1  NaN  3.0
2  1.0  4.0    | 2  1.0  4.0           | 2  1.0  4.0            | 2  1.0  4.0
3  2.0  NaN    | 3  2.0  NaN           | 3  2.0  NaN            | 3  2.0  NaN
MultiIndexmit Seriesundaxis=1
 pd.concat(
     [s1, s2],
     axis=1,
     keys=[('W', 'X'), ('W', 'Y')])
-----------------------------------
     W
     X    Y
1  NaN  3.0
2  1.0  4.0
3  2.0  NaN
Zwei DataFramemitaxis=1

Fügen Sie wie in den axis=0Beispielen keysEbenen zu a hinzu MultiIndex, diesmal jedoch zu dem im columnsAttribut gespeicherten Objekt .

 pd.concat(                     |  pd.concat(
     [d1, d2],                  |      [d1, d2],
     axis=1,                    |      axis=1,
     keys=['X', 'Y'])           |      keys=[('First', 'X'), ('Second', 'X')])
------------------------------- | --------------------------------------------
     X              Y           |   First           Second
     A    B    C    B    C    D |       X                X
1  NaN  NaN  NaN  0.4  0.5  0.6 |       A    B    C      B    C    D
2  0.1  0.2  0.3  0.4  0.5  0.6 | 1   NaN  NaN  NaN    0.4  0.5  0.6
3  0.1  0.2  0.3  NaN  NaN  NaN | 2   0.1  0.2  0.3    0.4  0.5  0.6
                                | 3   0.1  0.2  0.3    NaN  NaN  NaN
Seriesund DataFramemitaxis=1

Das ist schwierig. In diesem Fall kann ein Skalarschlüsselwert nicht als einzige Indexebene für das SeriesObjekt fungieren, wenn es zu einer Spalte wird, während es gleichzeitig als erste Ebene von a MultiIndexfür das Objekt fungiert DataFrame. Daher verwenden Pandas erneut das nameAttribut des SeriesObjekts als Quelle für den Spaltennamen.

 pd.concat(           |  pd.concat(
     [s1, d1],        |      [s1.rename('Z'), d1],
     axis=1,          |      axis=1,
     keys=['X', 'Y']) |      keys=['X', 'Y'])
--------------------- | --------------------------
   X    Y             |    X    Y
   0    A    B    C   |    Z    A    B    C
2  1  0.1  0.2  0.3   | 2  1  0.1  0.2  0.3
3  2  0.1  0.2  0.3   | 3  2  0.1  0.2  0.3
Einschränkungen keysund MultiIndexSchlussfolgerungen.

Pandas scheint nur Spaltennamen aus dem SeriesNamen abzuleiten , füllt jedoch nicht die Lücken, wenn eine analoge Verkettung zwischen Datenrahmen mit einer anderen Anzahl von Spaltenebenen durchgeführt wird.

d1_ = pd.concat(
    [d1], axis=1,
    keys=['One'])
d1_

   One
     A    B    C
2  0.1  0.2  0.3
3  0.1  0.2  0.3

Verketten Sie dies dann mit einem anderen Datenrahmen mit nur einer Ebene im Spaltenobjekt, und Pandas weigert sich, Tupel des MultiIndexObjekts zu erstellen und alle Datenrahmen so zu kombinieren, als ob eine einzelne Ebene von Objekten, Skalaren und Tupeln.

pd.concat([d1_, d2], axis=1)

   (One, A)  (One, B)  (One, C)    B    C    D
1       NaN       NaN       NaN  0.4  0.5  0.6
2       0.1       0.2       0.3  0.4  0.5  0.6
3       0.1       0.2       0.3  NaN  NaN  NaN

Pass a dictstatt alist

Wenn Sie ein Wörterbuch übergeben, pandas.concatwerden die Schlüssel aus dem Wörterbuch als keysParameter verwendet.

 # axis=0               |  # axis=1
 pd.concat(             |  pd.concat(
     {0: d1, 1: d2})    |      {0: d1, 1: d2}, axis=1)
----------------------- | -------------------------------
       A    B    C    D |      0              1
0 2  0.1  0.2  0.3  NaN |      A    B    C    B    C    D
  3  0.1  0.2  0.3  NaN | 1  NaN  NaN  NaN  0.4  0.5  0.6
1 1  NaN  0.4  0.5  0.6 | 2  0.1  0.2  0.3  0.4  0.5  0.6
  2  NaN  0.4  0.5  0.6 | 3  0.1  0.2  0.3  NaN  NaN  NaN

levels

Dies wird in Verbindung mit dem keysArgument verwendet. Wenn der levelsStandardwert von belassen wird None, verwendet Pandas die eindeutigen Werte jeder Ebene des Ergebnisses MultiIndexund verwendet diese als das im resultierenden index.levelsAttribut verwendete Objekt .

Ebenen : Liste der Sequenzen, Standard Keine
Spezifische Ebenen (eindeutige Werte), die zum Erstellen eines MultiIndex verwendet werden sollen. Andernfalls werden sie aus den Schlüsseln abgeleitet.

Wenn Pandas bereits darauf schließen, wie diese Ebenen aussehen sollten, welchen Vorteil gibt es dann, sie selbst festzulegen? Ich werde ein Beispiel zeigen und es Ihnen überlassen, sich andere Gründe auszudenken, warum dies nützlich sein könnte.

Beispiel

Gemäß der Dokumentation ist das levelsArgument eine Liste von Sequenzen. Dies bedeutet, dass wir eine andere pandas.Indexals eine dieser Sequenzen verwenden können.

Betrachten Sie den Datenrahmen df, der die Verkettung von d1, d2und istd3 :

df = pd.concat(
    [d1, d2, d3], axis=1,
    keys=['First', 'Second', 'Fourth'])

df

  First           Second           Fourth
      A    B    C      B    C    D      A    B    D
1   NaN  NaN  NaN    0.4  0.5  0.6    0.7  0.8  0.9
2   0.1  0.2  0.3    0.4  0.5  0.6    NaN  NaN  NaN
3   0.1  0.2  0.3    NaN  NaN  NaN    0.7  0.8  0.9

Die Ebenen des Spaltenobjekts sind:

print(df, *df.columns.levels, sep='\n')

Index(['First', 'Second', 'Fourth'], dtype='object')
Index(['A', 'B', 'C', 'D'], dtype='object')

Wenn wir suminnerhalb eines verwendengroupby wir:

df.groupby(axis=1, level=0).sum()

   First  Fourth  Second
1    0.0     2.4     1.5
2    0.6     0.0     1.5
3    0.6     2.4     0.0

Aber was wäre, wenn stattdessen ['First', 'Second', 'Fourth']keine anderen Kategorien mit dem Namen Thirdund fehlen würden Fifth? Und ich wollte, dass sie in die Ergebnisse von a aufgenommen werdengroupby Aggregation ? Wir können das tun, wenn wir eine hätten pandas.CategoricalIndex. Und das können wir mit dem levelsArgument vorab festlegen .

Definieren wir stattdessen Folgendes df:

cats = ['First', 'Second', 'Third', 'Fourth', 'Fifth']
lvl = pd.CategoricalIndex(cats, categories=cats, ordered=True)

df = pd.concat(
    [d1, d2, d3], axis=1,
    keys=['First', 'Second', 'Fourth'],
    levels=[lvl]
)

df

   First  Fourth  Second
1    0.0     2.4     1.5
2    0.6     0.0     1.5
3    0.6     2.4     0.0

Die erste Ebene des Spaltenobjekts lautet jedoch:

df.columns.levels[0]

CategoricalIndex(
    ['First', 'Second', 'Third', 'Fourth', 'Fifth'],
    categories=['First', 'Second', 'Third', 'Fourth', 'Fifth'],
    ordered=True, dtype='category')

Und unsere groupbyZusammenfassung sieht aus wie:

df.groupby(axis=1, level=0).sum()

   First  Second  Third  Fourth  Fifth
1    0.0     1.5    0.0     2.4    0.0
2    0.6     1.5    0.0     0.0    0.0
3    0.6     0.0    0.0     2.4    0.0

names

Dies wird verwendet, um die Ebenen eines Ergebnisses zu benennen MultiIndex. Die Länge der namesListe sollte mit der Anzahl der Ebenen in der resultierenden übereinstimmenMultiIndex .

Namen : Liste, Standard Keine
Namen für die Ebenen im resultierenden hierarchischen Index

 # axis=0                     |  # axis=1
 pd.concat(                   |  pd.concat(
     [d1, d2],                |      [d1, d2],
     keys=[0, 1],             |      axis=1, keys=[0, 1],
     names=['lvl0', 'lvl1'])  |      names=['lvl0', 'lvl1'])
----------------------------- | ----------------------------------
             A    B    C    D | lvl0    0              1
lvl0 lvl1                     | lvl1    A    B    C    B    C    D
0    2     0.1  0.2  0.3  NaN | 1     NaN  NaN  NaN  0.4  0.5  0.6
     3     0.1  0.2  0.3  NaN | 2     0.1  0.2  0.3  0.4  0.5  0.6
1    1     NaN  0.4  0.5  0.6 | 3     0.1  0.2  0.3  NaN  NaN  NaN
     2     NaN  0.4  0.5  0.6 |

verify_integrity

Selbsterklärende Dokumentation

verify_integrity : boolean, default False
Überprüfen Sie, ob die neue verkettete Achse Duplikate enthält. Dies kann im Verhältnis zur tatsächlichen Datenverkettung sehr teuer sein.

Da der resultierende Index verkettet d1und d2nicht eindeutig ist, würde die Integritätsprüfung fehlschlagen.

pd.concat([d1, d2])

     A    B    C    D
2  0.1  0.2  0.3  NaN
3  0.1  0.2  0.3  NaN
1  NaN  0.4  0.5  0.6
2  NaN  0.4  0.5  0.6

Und

pd.concat([d1, d2], verify_integrity=True)

> ValueError: Indizes haben überlappende Werte: [2]

piRSquared
quelle
23
Es wäre für die Community wirklich viel nützlicher, einfach eine Pull-Anfrage zu stellen, um einige fehlende Beispiele (nur ein paar) zu den Hauptdokumenten hinzuzufügen. SO ist nur durchsuchbar und nicht durchsuchbar; Ein weiterer Link zu den Dokumenten wäre hier nützlich - die überwiegende Mehrheit davon ist bereits gut und vollständig dokumentiert
Jeff
6
@ Jeff, es gibt Dimensionen meines Wachstums, die langsam waren. Die Verwendung von Git ist eine davon. Ich verspreche, dass ich damit anfangen möchte.
piRSquared
Die Verwendung pd.concat(..., levels=[lvl]).groupby(axis=1, level=0).sum()führt zu einem anderen Ergebnis als pd.concat(..., levels=[cats]).groupby(axis=1, level=0).sum(). Weißt du, warum? Die Dokumente sagen nur, levelssollte eine Liste von Sequenzen sein.
Unutbu
1
Tolle Antwort, aber ich denke, der Abschnitt darüber Passing a dict instead of a listbraucht ein Beispiel mit einem Diktat, keine Liste.
Unutbu
1
@unutbu Ich habe das dictBeispiel behoben, danke. Der Grund dafür ist, dass dies lvlein kategorialer Index ist und catsnur eine Liste. Bei der Gruppierung nach einem Kategorietyp werden die fehlenden Kategorien gegebenenfalls mit Nullen und Nullen gefüllt. Siehe dies
piRSquared