Bagaimana cara menyimpan indeks saat menggunakan gabungan pandas

126

Saya ingin menggabungkan dua DataFrames, dan menyimpan indeks dari bingkai pertama sebagai indeks pada kumpulan data yang digabungkan. Namun, ketika saya melakukan penggabungan, DataFrame yang dihasilkan memiliki indeks integer. Bagaimana saya dapat menentukan bahwa saya ingin menyimpan indeks dari bingkai data kiri?

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

EDIT: Beralih ke kode contoh yang dapat direproduksi dengan mudah

DanB
sumber
2
jika Anda menggabungkan pada kolom tertentu, tidak jelas indeks mana yang akan digunakan (jika keduanya berbeda).
bonobo

Jawaban:

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

Catatan: untuk beberapa operasi penggabungan kiri, Anda mungkin akan mendapatkan lebih banyak baris jika ada beberapa kecocokan antara adan bdan Anda perlu menghapus duplikat ( dokumentasi untuk deduplikasi ). Inilah mengapa panda tidak menyimpan indeks untuk Anda.

Wouter Overmeire
sumber
4
Sangat pintar. a.merge (b, how = "left"). set_index (a.index) juga berfungsi, tetapi tampaknya kurang kuat (karena bagian pertama kehilangan nilai indeks ke a sebelum menyetel ulang.)
DanB
11
Untuk kasus khusus ini, keduanya setara. Tetapi untuk banyak operasi penggabungan, bingkai yang dihasilkan tidak memiliki jumlah baris yang sama dengan abingkai aslinya . reset_index memindahkan indeks ke kolom biasa dan set_index dari kolom ini setelah penggabungan juga menangani saat baris a digandakan / dihapus karena operasi penggabungan.
Wouter Overmeire
1
@Wouter Saya ingin tahu mengapa penggabungan kiri akan mengindeks ulang secara default. Dimana saya bisa belajar lebih banyak?
Matius
7
Bagus! Untuk menghindari secara eksplisit menentukan nama indeks yang saya gunakan a.reset_index().merge(b, how="left").set_index(a.index.names).
Truls
3
Panda mengira API menyerang lagi.
Henry Henrinson
7

Anda dapat membuat salinan indeks di dataframe kiri dan melakukan penggabungan.

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

Saya menemukan metode sederhana ini sangat berguna saat bekerja dengan kerangka data besar dan menggunakan pd.merge_asof()(atau dd.merge_asof()).

Pendekatan ini akan lebih baik jika pengaturan ulang indeks mahal (dataframe besar).

Matthew Son
sumber
1
Inilah jawaban terbaik. Ada banyak alasan mengapa Anda ingin mempertahankan indeks lama Anda selama penggabungan (dan jawaban yang diterima tidak mempertahankan indeks, itu hanya menyetel ulang). Ini membantu ketika Anda mencoba menggabungkan lebih dari 2 kerangka data, dan seterusnya ...
Marses
2
Solusi unggul karena mempertahankan nama indeks (asli)
Martien Lubberink
suara positif tetapi berhati-hatilah dengan peringatan, saat menggunakan multi-indeks, indeks Anda akan disimpan sebagai tupel dalam satu kolom yang disebut [copy_index]
geekidharsh
6

Ada solusi non-pd.merge. Menggunakan mapdanset_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

Dan, tidak memperkenalkan indexnama tiruan untuk indeks.

Nol
sumber
1
Ini tampaknya lebih unggul dari jawaban yang diterima karena mungkin akan bekerja lebih baik dengan kasus tepi seperti multi indeks. Adakah yang bisa mengomentari ini?
BallpointBen
1
pertanyaan, bagaimana jika Anda perlu menetapkan beberapa kolom, apakah pendekatan ini akan berhasil atau hanya terbatas pada 1 bidang?
Yuca
@Yuca: Ini mungkin tidak akan berfungsi dengan banyak kolom, karena ketika Anda membuat subset beberapa kolom, Anda berakhir dengan a pd.Dataframedan bukan a pd.Series. The .map()Metode hanya didefinisikan untuk pd.Series. Artinya: a[['to_merge_on_1', 'to_merge_on_2']].map(...)tidak akan berhasil.
Dataman
4
df1 = df1.merge(
        df2, how="inner", left_index=True, right_index=True
    )

Hal ini memungkinkan untuk mempertahankan indeks df1

Supratik Majumdar
sumber
Tampaknya untuk bekerja, tapi ketika saya menggunakannya dengan on=list_of_cols], bertentangan dokumentasi: If joining columns on columns, the DataFrame indexes *will be ignored*. Apakah salah satu penggunaan indeks vs. kolom diutamakan?
Itamar Katz
0

Pikir saya telah menemukan solusi yang berbeda. Saya bergabung dengan tabel kiri pada nilai indeks dan tabel kanan pada nilai kolom berdasarkan indeks tabel kiri. Apa yang saya lakukan adalah penggabungan normal:

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

Kemudian saya mengambil nomor indeks baru dari tabel gabungan dan meletakkannya di kolom baru bernama Nomor Garis Sentimen:

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

Kemudian saya secara manual mengatur indeks kembali ke indeks tabel kiri asli berdasarkan kolom yang sudah ada yang disebut Nomor Baris (nilai kolom tempat saya bergabung dari indeks tabel kiri):

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

Kemudian dihapus nama index dari Line Number agar tetap kosong:

First10ReviewsJoined.index.name = None

Mungkin sedikit hack tetapi tampaknya berfungsi dengan baik dan relatif sederhana. Selain itu, tebak itu mengurangi risiko duplikat / mengacaukan data Anda. Semoga semuanya masuk akal.

pengembang
sumber
0

Pilihan sederhana lainnya adalah mengganti nama indeks menjadi sebelumnya:

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

merge mempertahankan urutan pada dataframe 'a', tetapi hanya menyetel ulang indeks sehingga simpan untuk menggunakan set_axis

lisrael1
sumber