So halten Sie den Index bei Verwendung von Pandas Merge

126

Ich möchte zwei zusammenführen DataFramesund den Index aus dem ersten Frame als Index für den zusammengeführten Datensatz beibehalten. Wenn ich jedoch die Zusammenführung durchführe, hat der resultierende DataFrame einen ganzzahligen Index. Wie kann ich angeben, dass der Index vom linken Datenrahmen ferngehalten werden soll?

In [4]: a = pd.DataFrame({'col1': {'a': 1, 'b': 2, 'c': 3}, 
                          'to_merge_on': {'a': 1, 'b': 3, 'c': 4}})

In [5]: b = pd.DataFrame({'col2': {0: 1, 1: 2, 2: 3}, 
                          'to_merge_on': {0: 1, 1: 3, 2: 5}})

In [6]: a
Out[6]:
   col1  to_merge_on
a     1            1
b     2            3
c     3            4

In [7]: b
Out[7]:
   col2  to_merge_on
0     1            1
1     2            3
2     3            5

In [8]: a.merge(b, how='left')
Out[8]:
   col1  to_merge_on  col2
0     1            1   1.0
1     2            3   2.0
2     3            4   NaN

In [9]: _.index
Out[9]: Int64Index([0, 1, 2], dtype='int64')

BEARBEITEN: Auf Beispielcode umgestellt, der leicht reproduziert werden kann

DanB
quelle
2
Wenn Sie in einer bestimmten Spalte zusammenführen, ist nicht klar, welche Indizes verwendet werden sollen (falls beide unterschiedlich sind).
Bonobo

Antworten:

161
In [5]: a.reset_index().merge(b, how="left").set_index('index')
Out[5]:
       col1  to_merge_on  col2
index
a         1            1     1
b         2            3     2
c         3            4   NaN

Hinweis: Bei einigen Linkszusammenführungsvorgängen werden möglicherweise mehr Zeilen angezeigt, wenn zwischen aund mehrere Übereinstimmungen bestehen bund Sie eine Deduplizierung benötigen ( Dokumentation zur Deduplizierung ). Aus diesem Grund behält Pandas den Index nicht für Sie.

Wouter Overmeire
quelle
4
Sehr schlau. a.merge (b, how = "left"). set_index (a.index) funktioniert ebenfalls, scheint jedoch weniger robust zu sein (da der erste Teil die Indexwerte auf a verliert, bevor sie zurückgesetzt werden.)
DanB
11
Für diesen speziellen Fall sind diese gleichwertig. Bei vielen Zusammenführungsvorgängen weist der resultierende Frame jedoch nicht die gleiche Anzahl von Zeilen auf wie der ursprüngliche aFrame. reset_index verschiebt den Index in eine reguläre Spalte und set_index aus dieser Spalte nach dem Zusammenführen sorgt auch dafür, dass Zeilen von a aufgrund des Zusammenführungsvorgangs dupliziert / entfernt werden.
Wouter Overmeire
1
@Wouter Ich würde gerne wissen, warum eine Linkszusammenführung standardmäßig neu indiziert wird. Wo kann ich mehr lernen?
Matthew
7
Nett! Um zu vermeiden, dass der von mir verwendete Indexname explizit angegeben wird a.reset_index().merge(b, how="left").set_index(a.index.names).
Truls
3
Pandas dachte schlecht, API schlägt wieder zu.
Henry Henrinson
7

Sie können eine Kopie des Index im linken Datenrahmen erstellen und zusammenführen.

a['copy_index'] = a.index
a.merge(b, how='left')

Ich fand diese einfache Methode sehr nützlich, wenn ich mit großen Datenrahmen arbeitete und pd.merge_asof()(oder dd.merge_asof()) verwendete.

Dieser Ansatz wäre überlegen, wenn das Zurücksetzen des Index teuer ist (großer Datenrahmen).

Matthew Son
quelle
1
Dies ist die beste Antwort. Es gibt viele Gründe, warum Sie Ihre alten Indizes während einer Zusammenführung beibehalten möchten (und die akzeptierte Antwort behält keine Indizes bei, sondern setzt sie nur zurück). Es hilft, wenn Sie versuchen, mehr als 2 Datenrahmen zusammenzuführen, und so weiter ...
Marses
2
Überlegene Lösung, da der (ursprüngliche)
Indexname erhalten bleibt
Wenn Sie Multi-Index verwenden, werden Ihre Indizes als Tupel in einer einzigen Spalte namens [copy_index]
gespeichert
6

Es gibt eine Lösung ohne pd.merge. Verwenden von mapundset_index

In [1744]: a.assign(col2=a['to_merge_on'].map(b.set_index('to_merge_on')['col2']))
Out[1744]:
   col1  to_merge_on  col2
a     1            1   1.0
b     2            3   2.0
c     3            4   NaN

Und führt keinen Dummy- indexNamen für den Index ein.

Null
quelle
1
Dies scheint der akzeptierten Antwort überlegen zu sein, da es wahrscheinlich besser mit Randfällen wie Multi-Indizes funktioniert. Kann jemand dies kommentieren?
BallpointBen
1
Frage: Was wäre, wenn Sie mehrere Spalten zuweisen müssten, würde dieser Ansatz funktionieren oder ist er auf nur ein Feld beschränkt?
Yuca
@Yuca: Dies funktioniert möglicherweise nicht mit mehreren Spalten, da Sie beim Unterteilen mehrerer Spalten ein pd.Dataframeund kein a erhalten pd.Series. Die .map()Methode ist nur für die definiert pd.Series. Das soll heißen: a[['to_merge_on_1', 'to_merge_on_2']].map(...)funktioniert nicht.
Dataman
4
df1 = df1.merge(
        df2, how="inner", left_index=True, right_index=True
    )

Dadurch kann der Index von df1 beibehalten werden

Supratik Majumdar
quelle
Es scheint zu funktionieren, aber wenn ich es benutze on=list_of_cols], widerspricht es der Dokumentation : If joining columns on columns, the DataFrame indexes *will be ignored*. Hat die Verwendung von Indizes gegenüber Spalten Vorrang?
Itamar Katz
0

Ich glaube, ich habe eine andere Lösung gefunden. Ich habe die linke Tabelle mit dem Indexwert und die rechte Tabelle mit einem Spaltenwert verbunden, der auf dem Index der linken Tabelle basiert. Was ich getan habe, war eine normale Zusammenführung:

First10ReviewsJoined = pd.merge(First10Reviews, df, left_index=True, right_on='Line Number')

Dann habe ich die neuen Indexnummern aus der zusammengeführten Tabelle abgerufen und in eine neue Spalte mit dem Namen Sentiment Line Number eingefügt:

First10ReviewsJoined['Sentiment Line Number']= First10ReviewsJoined.index.tolist()

Dann setze ich den Index manuell auf den ursprünglichen Index der linken Tabelle zurück, basierend auf der bereits vorhandenen Spalte mit dem Namen Zeilennummer (der Spaltenwert, den ich aus dem Index der linken Tabelle hinzugefügt habe):

First10ReviewsJoined.set_index('Line Number', inplace=True)

Entfernen Sie dann den Indexnamen der Zeilennummer, damit er leer bleibt:

First10ReviewsJoined.index.name = None

Vielleicht ein bisschen hacken, scheint aber gut und relativ einfach zu funktionieren. Vermutlich verringert es auch das Risiko von Duplikaten / Durcheinander Ihrer Daten. Hoffentlich macht das alles Sinn.

der Entwickler
quelle
0

Eine andere einfache Option besteht darin, den Index in den vorherigen umzubenennen:

a.merge(b, how="left").set_axis(a.index)

Beim Zusammenführen wird die Reihenfolge im Datenrahmen 'a' beibehalten, der Index wird jedoch nur zurückgesetzt, sodass die Verwendung von set_axis gespeichert wird

lisrael1
quelle