Jak zachować indeks podczas łączenia pand

126

Chciałbym połączyć dwa DataFramesi zachować indeks z pierwszej klatki jako indeks scalonego zbioru danych. Jednak gdy wykonuję scalanie, wynikowa ramka DataFrame ma indeks całkowity. Jak mogę określić, że chcę zachować indeks z lewej ramki danych?

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')

EDYCJA: Przełączono na przykładowy kod, który można łatwo odtworzyć

DanB
źródło
2
jeśli scalasz w określonej kolumnie, nie jest jasne, których indeksów użyć (w przypadku, gdy są różne).
bonobo

Odpowiedzi:

162
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

Uwaga: w przypadku niektórych operacji scalania po lewej stronie możesz otrzymać więcej wierszy, jeśli istnieje wiele dopasowań między ai, ba będziesz musiał dokonać deduplikacji ( dokumentacja dotycząca deduplikacji ). Dlatego pandy nie przechowują dla ciebie indeksu.

Wouter Overmeire
źródło
4
Bardzo mądry. a.merge (b, how = "left"). set_index (a.index) również działa, ale wydaje się mniej stabilny (ponieważ pierwsza część traci wartości indeksu do a, zanim je zresetuje).
DanB
11
W tym konkretnym przypadku są one równoważne. Ale w przypadku wielu operacji scalania wynikowa ramka nie ma takiej samej liczby wierszy, jak oryginalna aramka. reset_index przenosi indeks do zwykłej kolumny, a set_index z tej kolumny po scaleniu dba również o to, gdy wiersze a są duplikowane / usuwane z powodu operacji scalania.
Wouter Overmeire
1
@Wouter Chciałbym wiedzieć, dlaczego lewe scalanie zostanie domyślnie ponownie zindeksowane. Gdzie mogę dowiedzieć się więcej?
Matthew,
7
Miły! Aby uniknąć jawnego określenia nazwy indeksu, której używam a.reset_index().merge(b, how="left").set_index(a.index.names).
Truls
3
Pandy źle pomyśleli, że API znów uderza.
Henry Henrinson,
7

Możesz zrobić kopię indeksu w lewej ramce danych i scalić.

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

Uważam, że ta prosta metoda jest bardzo przydatna podczas pracy z dużą ramką danych i używania pd.merge_asof()(lub dd.merge_asof()).

Takie podejście byłoby lepsze, gdy resetowanie indeksu jest drogie (duża ramka danych).

Matthew Son
źródło
1
To najlepsza odpowiedź. Istnieje wiele powodów, dla których chciałbyś zachować swoje stare indeksy podczas scalania (a zaakceptowana odpowiedź nie zachowuje indeksów, po prostu je resetuje). Pomaga, gdy próbujesz scalić więcej niż 2 ramki danych itd.
Marses
2
Doskonałe rozwiązanie, ponieważ zachowuje (oryginalną) nazwę indeksu
Martien Lubberink,
przegłosowano, ale po prostu uważaj na zastrzeżenie, gdy używasz wielu indeksów, twoje indeksy będą przechowywane jako krotka w jednej kolumnie o nazwie [copy_index]
geekidharsh.
6

Istnieje rozwiązanie inne niż pd.merge. Korzystanie mapiset_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

I nie wprowadza fikcyjnej indexnazwy indeksu.

Zero
źródło
1
Wydaje się to lepsze od akceptowanej odpowiedzi, ponieważ prawdopodobnie będzie działać lepiej w przypadkach skrajnych, takich jak wiele indeksów. Czy ktoś może to skomentować?
BallpointBen
1
pytanie, co jeśli musisz przypisać wiele kolumn, czy to podejście zadziała, czy jest ograniczone tylko do 1 pola?
Yuca
@Yuca: To prawdopodobnie nie zadziała z wieloma kolumnami, ponieważ kiedy podbijesz wiele kolumn, otrzymasz a, pd.Dataframea nie pd.Series. .map()Sposób jest określone tylko dla pd.Series. To znaczy, że: a[['to_merge_on_1', 'to_merge_on_2']].map(...)nie zadziała.
Dataman
4
df1 = df1.merge(
        df2, how="inner", left_index=True, right_index=True
    )

Pozwala to zachować indeks df1

Supratik Majumdar
źródło
Wydaje się do pracy, ale kiedy używać go on=list_of_cols], stoi w sprzeczności z dokumentacją: If joining columns on columns, the DataFrame indexes *will be ignored*. Czy pierwszeństwo ma używanie indeksów i kolumn?
Itamar Katz
0

Myślę, że wymyśliłem inne rozwiązanie. Dołączyłem do lewej tabeli na wartości indeksu i prawej tabeli na wartości kolumny opartej na indeksie lewej tabeli. To, co zrobiłem, było normalnym połączeniem:

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

Następnie odzyskałem nowe numery indeksu ze scalonej tabeli i umieściłem je w nowej kolumnie o nazwie Sentiment Line Number:

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

Następnie ręcznie ustawiłem indeks z powrotem na oryginalny, lewy indeks tabeli w oparciu o wcześniej istniejącą kolumnę o nazwie Numer wiersza (wartość kolumny, do której dołączyłem z lewego indeksu tabeli):

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

Następnie usunięto nazwę indeksu Line Number, aby pozostała pusta:

First10ReviewsJoined.index.name = None

Może trochę hack, ale wydaje się działać dobrze i stosunkowo prosto. Zgadnij, że zmniejsza to ryzyko duplikowania / zepsucia danych. Mam nadzieję, że to wszystko ma sens.

Deweloper
źródło
0

Inną prostą opcją jest zmiana nazwy indeksu na wcześniejszą:

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

merge zachowuje kolejność w dataframe 'a', ale po prostu resetuje indeks, więc można go zapisać do użycia set_axis

lisrael1
źródło