Penggabungan Pandas 101

Dec 06 2018
  • Bagaimana cara melakukan ( INNER| ( LEFT| RIGHT| FULL) OUTER) JOINdengan panda?
  • Bagaimana cara menambahkan NaN untuk baris yang hilang setelah penggabungan?
  • Bagaimana cara menghapus NaN setelah penggabungan?
  • Bisakah saya menggabungkan indeks?
  • Bergabung dengan panda?
  • Bagaimana cara menggabungkan beberapa DataFrame?
  • merge? join? concat? update? WHO? Apa? Mengapa?!

... dan banyak lagi. Saya telah melihat pertanyaan berulang ini menanyakan tentang berbagai aspek fungsi gabungan panda. Sebagian besar informasi terkait penggabungan dan berbagai kasus penggunaannya saat ini terpecah-pecah di lusinan pos yang tidak dapat ditelusuri dengan kata-kata buruk. Tujuannya di sini adalah menyusun beberapa poin yang lebih penting untuk anak cucu.

QnA ini dimaksudkan untuk menjadi angsuran berikutnya dalam serangkaian panduan pengguna yang bermanfaat tentang idiom umum panda (lihat posting ini tentang berputar , dan posting ini tentang penggabungan , yang akan saya bahas nanti).

Harap dicatat bahwa posting ini tidak dimaksudkan sebagai pengganti dokumentasi , jadi harap baca itu juga! Beberapa contoh diambil dari sana.

Jawaban

696 cs95 Dec 06 2018 at 13:41

Posting ini bertujuan untuk memberi pembaca primer tentang penggabungan rasa SQL dengan panda, cara menggunakannya, dan kapan tidak menggunakannya.

Secara khusus, inilah yang akan dilakukan posting ini:

  • Dasar - jenis gabungan (kiri, kanan, luar, dalam)

    • penggabungan dengan nama kolom yang berbeda
    • menghindari duplikat kolom kunci gabungan dalam keluaran
  • Penggabungan dengan indeks dalam kondisi berbeda

    • efektif menggunakan indeks bernama Anda
    • menggabungkan kunci sebagai indeks satu dan kolom lainnya
  • Penggabungan multiway pada kolom dan indeks (unik dan tidak unik)

  • Alternatif penting untuk mergedanjoin

Apa yang posting ini tidak akan melalui:

  • Diskusi dan pengaturan waktu terkait kinerja (untuk saat ini). Sebagian besar menyebutkan alternatif yang lebih baik, jika sesuai.
  • Menangani sufiks, menghapus kolom ekstra, mengganti nama keluaran, dan kasus penggunaan khusus lainnya. Ada posting lain (baca: lebih baik) yang berhubungan dengan itu, jadi cari tahu!

Catatan
Kebanyakan contoh default untuk operasi INNER JOIN saat mendemonstrasikan berbagai fitur, kecuali ditentukan lain.

Lebih lanjut, semua DataFrames di sini dapat disalin dan direplikasi sehingga Anda dapat bermain dengannya. Juga, lihat posting ini tentang cara membaca DataFrames dari clipboard Anda.

Terakhir, semua representasi visual dari operasi JOIN telah digambar dengan tangan menggunakan Google Gambar. Inspirasi dari sini .

Cukup Bicara, tunjukkan saja cara menggunakannya merge!

Mendirikan

np.random.seed(0)
left = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'value': np.random.randn(4)})    
right = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'value': np.random.randn(4)})
  
left

  key     value
0   A  1.764052
1   B  0.400157
2   C  0.978738
3   D  2.240893

right

  key     value
0   B  1.867558
1   D -0.977278
2   E  0.950088
3   F -0.151357

Demi kesederhanaan, kolom kunci memiliki nama yang sama (untuk saat ini).

Sebuah INNER JOIN diwakili oleh

Perhatikan
Ini, bersama dengan angka-angka yang akan datang, semuanya mengikuti konvensi ini:

  • biru menunjukkan baris yang ada di hasil penggabungan
  • merah menunjukkan baris yang dikecualikan dari hasil (yaitu, dihapus)
  • hijau menunjukkan nilai yang hilang yang diganti dengan NaNs dalam hasil

Untuk melakukan INNER JOIN, panggil mergeDataFrame kiri, tentukan DataFrame kanan dan kunci penghubung (paling tidak) sebagai argumen.

left.merge(right, on='key')
# Or, if you want to be explicit
# left.merge(right, on='key', how='inner')

  key   value_x   value_y
0   B  0.400157  1.867558
1   D  2.240893 -0.977278

Ini hanya mengembalikan baris dari leftdan rightyang berbagi kunci yang sama (dalam contoh ini, "B" dan "D).

A LEFT OUTER JOIN , atau LEFT JOIN diwakili oleh

Ini dapat dilakukan dengan menentukan how='left'.

left.merge(right, on='key', how='left')

  key   value_x   value_y
0   A  1.764052       NaN
1   B  0.400157  1.867558
2   C  0.978738       NaN
3   D  2.240893 -0.977278

Perhatikan dengan cermat penempatan NaN di sini. Jika Anda menentukan how='left', maka hanya kunci dari leftyang digunakan, dan data yang hilang dari rightdiganti oleh NaN.

Dan serupa, untuk RIGHT OUTER JOIN , atau RIGHT JOIN yang ...

... tentukan how='right':

left.merge(right, on='key', how='right')

  key   value_x   value_y
0   B  0.400157  1.867558
1   D  2.240893 -0.977278
2   E       NaN  0.950088
3   F       NaN -0.151357

Di sini, kunci dari rightdigunakan, dan data yang hilang dari leftdiganti dengan NaN.

Akhirnya, untuk FULL OUTER JOIN , diberikan oleh

tentukan how='outer'.

left.merge(right, on='key', how='outer')

  key   value_x   value_y
0   A  1.764052       NaN
1   B  0.400157  1.867558
2   C  0.978738       NaN
3   D  2.240893 -0.977278
4   E       NaN  0.950088
5   F       NaN -0.151357

Ini menggunakan kunci dari kedua bingkai, dan NaN disisipkan untuk baris yang hilang di keduanya.

Dokumentasi merangkum berbagai penggabungan ini dengan baik:

GABUNG Lainnya - KIRI-Tidak Termasuk, KANAN-Tidak Termasuk, dan PENUH-Tidak Termasuk / ANTI JOIN

Jika Anda membutuhkan KIRI-Tidak Termasuk GABUNG dan KANAN-Tidak Termasuk JOIN dalam dua langkah.

Untuk LEFT-Exc Included JOIN, direpresentasikan sebagai

Mulailah dengan melakukan LEFT OUTER JOIN dan kemudian memfilter (tidak termasuk!) Baris yang lefthanya berasal dari ,

(left.merge(right, on='key', how='left', indicator=True)
     .query('_merge == "left_only"')
     .drop('_merge', 1))

  key   value_x  value_y
0   A  1.764052      NaN
2   C  0.978738      NaN

Dimana,

left.merge(right, on='key', how='left', indicator=True)

  key   value_x   value_y     _merge
0   A  1.764052       NaN  left_only
1   B  0.400157  1.867558       both
2   C  0.978738       NaN  left_only
3   D  2.240893 -0.977278       both

Dan demikian pula, untuk GABUNG KANAN-Tidak Termasuk,

(left.merge(right, on='key', how='right', indicator=True)
     .query('_merge == "right_only"')
     .drop('_merge', 1))

  key  value_x   value_y
2   E      NaN  0.950088
3   F      NaN -0.151357

Terakhir, jika Anda diminta untuk melakukan penggabungan yang hanya mempertahankan kunci dari kiri atau kanan, tetapi tidak keduanya (IOW, melakukan ANTI-JOIN ),

Anda dapat melakukan ini dengan cara yang sama—

(left.merge(right, on='key', how='outer', indicator=True)
     .query('_merge != "both"')
     .drop('_merge', 1))

  key   value_x   value_y
0   A  1.764052       NaN
2   C  0.978738       NaN
4   E       NaN  0.950088
5   F       NaN -0.151357

Nama berbeda untuk kolom kunci

Jika kolom kunci diberi nama berbeda — misalnya, lefthas keyLeft, dan righthas keyRightbukannya key— maka Anda harus menentukan left_ondan right_onsebagai argumen alih-alih on:

left2 = left.rename({'key':'keyLeft'}, axis=1)
right2 = right.rename({'key':'keyRight'}, axis=1)

left2
 
  keyLeft     value
0       A  1.764052
1       B  0.400157
2       C  0.978738
3       D  2.240893

right2

  keyRight     value
0        B  1.867558
1        D -0.977278
2        E  0.950088
3        F -0.151357
left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')

  keyLeft   value_x keyRight   value_y
0       B  0.400157        B  1.867558
1       D  2.240893        D -0.977278

Menghindari kolom kunci duplikat dalam keluaran

Saat menggabungkan keyLeftdari leftdan keyRightdari right, jika Anda hanya menginginkan salah satu keyLeftatau keyRight(tetapi tidak keduanya) pada keluaran, Anda dapat mulai dengan menyetel indeks sebagai langkah awal.

left3 = left2.set_index('keyLeft')
left3.merge(right2, left_index=True, right_on='keyRight')
    
    value_x keyRight   value_y
0  0.400157        B  1.867558
1  2.240893        D -0.977278

Bandingkan ini dengan output dari perintah sebelumnya (yaitu, output dari left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')), Anda akan melihat keyLeftada yang hilang. Anda dapat mengetahui kolom mana yang harus disimpan berdasarkan indeks frame mana yang ditetapkan sebagai kuncinya. Ini mungkin penting ketika, katakanlah, melakukan beberapa operasi OUTER JOIN.

Menggabungkan hanya satu kolom dari salah satu DataFrames

Misalnya, pertimbangkan

right3 = right.assign(newcol=np.arange(len(right)))
right3
  key     value  newcol
0   B  1.867558       0
1   D -0.977278       1
2   E  0.950088       2
3   F -0.151357       3

Jika Anda hanya diminta untuk menggabungkan "new_val" (tanpa kolom lain), Anda biasanya hanya dapat membuat subset kolom sebelum menggabungkan:

left.merge(right3[['key', 'newcol']], on='key')

  key     value  newcol
0   B  0.400157       0
1   D  2.240893       1

Jika Anda melakukan LEFT OUTER JOIN, solusi yang lebih berkinerja akan melibatkan map:

# left['newcol'] = left['key'].map(right3.set_index('key')['newcol']))
left.assign(newcol=left['key'].map(right3.set_index('key')['newcol']))

  key     value  newcol
0   A  1.764052     NaN
1   B  0.400157     0.0
2   C  0.978738     NaN
3   D  2.240893     1.0

Seperti yang disebutkan, ini mirip dengan, tetapi lebih cepat dari

left.merge(right3[['key', 'newcol']], on='key', how='left')

  key     value  newcol
0   A  1.764052     NaN
1   B  0.400157     0.0
2   C  0.978738     NaN
3   D  2.240893     1.0

Menggabungkan beberapa kolom

Untuk bergabung di lebih dari satu kolom, tentukan daftar untuk on(atau left_ondan right_on, yang sesuai).

left.merge(right, on=['key1', 'key2'] ...)

Atau, jika namanya berbeda,

left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])

merge*Operasi dan fungsi berguna lainnya

Bagian ini hanya membahas dasar-dasarnya, dan dirancang hanya untuk membangkitkan selera makan Anda. Untuk contoh dan kasus, lihat dokumentasi di merge, join, danconcat serta link ke spesifikasi fungsi.


Berbasis indeks * -JOIN (+ indeks-kolom merges)

Mendirikan

np.random.seed([3, 14])
left = pd.DataFrame({'value': np.random.randn(4)}, index=['A', 'B', 'C', 'D'])    
right = pd.DataFrame({'value': np.random.randn(4)}, index=['B', 'D', 'E', 'F'])
left.index.name = right.index.name = 'idxkey'

left
           value
idxkey          
A      -0.602923
B      -0.402655
C       0.302329
D      -0.524349

right
 
           value
idxkey          
B       0.543843
D       0.013135
E      -0.326498
F       1.385076

Biasanya, penggabungan indeks akan terlihat seperti ini:

left.merge(right, left_index=True, right_index=True)


         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Dukungan untuk nama indeks

Jika indeks Anda diberi nama, maka pengguna v0.23 juga dapat menentukan nama level untuk on(atau left_ondan right_onsesuai kebutuhan).

left.merge(right, on='idxkey')

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Menggabungkan indeks satu, kolom lain

Dimungkinkan (dan cukup sederhana) untuk menggunakan indeks satu, dan kolom lain, untuk melakukan penggabungan. Sebagai contoh,

left.merge(right, left_on='key1', right_index=True)

Atau sebaliknya ( right_on=...dan left_index=True).

right2 = right.reset_index().rename({'idxkey' : 'colkey'}, axis=1)
right2
 
  colkey     value
0      B  0.543843
1      D  0.013135
2      E -0.326498
3      F  1.385076

left.merge(right2, left_index=True, right_on='colkey')

    value_x colkey   value_y
0 -0.402655      B  0.543843
1 -0.524349      D  0.013135

Dalam kasus khusus ini, indeks untuk leftdiberi nama, sehingga Anda juga dapat menggunakan nama indeks dengan left_on, seperti ini:

left.merge(right2, left_on='idxkey', right_on='colkey')

    value_x colkey   value_y
0 -0.402655      B  0.543843
1 -0.524349      D  0.013135

DataFrame.join
Selain itu, ada opsi ringkas lainnya. Anda dapat menggunakan DataFrame.joindefault mana yang akan digabungkan pada indeks. DataFrame.joinmelakukan LEFT OUTER JOIN secara default, jadi how='inner'diperlukan di sini.

left.join(right, how='inner', lsuffix='_x', rsuffix='_y')

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Perhatikan bahwa saya perlu menentukan argumen lsuffixdan rsuffixkarena joinjika tidak akan terjadi kesalahan:

left.join(right)
ValueError: columns overlap but no suffix specified: Index(['value'], dtype='object')
 

Karena nama kolomnya sama. Ini tidak akan menjadi masalah jika nama mereka berbeda.

left.rename(columns={'value':'leftvalue'}).join(right, how='inner')

        leftvalue     value
idxkey                     
B       -0.402655  0.543843
D       -0.524349  0.013135

pd.concat
Terakhir, sebagai alternatif untuk gabungan berbasis indeks, Anda dapat menggunakan pd.concat:

pd.concat([left, right], axis=1, sort=False, join='inner')

           value     value
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Abaikan join='inner'jika Anda membutuhkan FULL OUTER JOIN (default):

pd.concat([left, right], axis=1, sort=False)

      value     value
A -0.602923       NaN
B -0.402655  0.543843
C  0.302329       NaN
D -0.524349  0.013135
E       NaN -0.326498
F       NaN  1.385076

Untuk informasi lebih lanjut, lihat posting kanonik ini pd.concatoleh @piRSquared .


Generalisasi: menggunakan mergebeberapa DataFrames

Seringkali, situasi muncul ketika beberapa DataFrame akan digabungkan. Secara naif, ini dapat dilakukan dengan merangkai mergepanggilan:

df1.merge(df2, ...).merge(df3, ...)

Namun, ini dengan cepat menjadi tidak terkendali untuk banyak DataFrame. Selain itu, mungkin perlu untuk menggeneralisasi sejumlah DataFrames yang tidak diketahui.

Di sini saya perkenalkan pd.concatuntuk gabungan multi-arah pada kunci unik , dan DataFrame.joinuntuk gabungan multi-arah pada kunci non-unik . Pertama, penyiapan.

# Setup.
np.random.seed(0)
A = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'valueA': np.random.randn(4)})    
B = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'valueB': np.random.randn(4)})
C = pd.DataFrame({'key': ['D', 'E', 'J', 'C'], 'valueC': np.ones(4)})
dfs = [A, B, C] 

# Note, the "key" column values are unique, so the index is unique.
A2 = A.set_index('key')
B2 = B.set_index('key')
C2 = C.set_index('key')

dfs2 = [A2, B2, C2]

Penggabungan multi cara pada kunci unik (atau indeks)

Jika kunci Anda (di sini, kunci bisa berupa kolom atau indeks) unik, Anda dapat menggunakan pd.concat. Perhatikan bahwa pd.concatmenggabungkan DataFrames pada indeks .

# merge on `key` column, you'll need to set the index before concatenating
pd.concat([
    df.set_index('key') for df in dfs], axis=1, join='inner'
).reset_index()

  key    valueA    valueB  valueC
0   D  2.240893 -0.977278     1.0

# merge on `key` index
pd.concat(dfs2, axis=1, sort=False, join='inner')

       valueA    valueB  valueC
key                            
D    2.240893 -0.977278     1.0

Abaikan join='inner'untuk FULL OUTER JOIN. Perhatikan bahwa Anda tidak dapat menentukan gabungan LEFT atau RIGHT OUTER (jika Anda membutuhkan ini, gunakan join, dijelaskan di bawah).

Multiway menggabungkan kunci dengan duplikat

concatcepat, tetapi memiliki kekurangan. Itu tidak bisa menangani duplikat.

A3 = pd.DataFrame({'key': ['A', 'B', 'C', 'D', 'D'], 'valueA': np.random.randn(5)})
pd.concat([df.set_index('key') for df in [A3, B, C]], axis=1, join='inner')
ValueError: Shape of passed values is (3, 4), indices imply (3, 2)

Dalam situasi ini, kita dapat menggunakan joinkarena dapat menangani kunci non-unik (perhatikan bahwa joinmenggabungkan DataFrames pada indeksnya; ia memanggil di mergebawah tenda dan melakukan LEFT OUTER JOIN kecuali ditentukan lain).

# join on `key` column, set as the index first
# For inner join. For left join, omit the "how" argument.
A.set_index('key').join(
    [df.set_index('key') for df in (B, C)], how='inner').reset_index()

  key    valueA    valueB  valueC
0   D  2.240893 -0.977278     1.0

# join on `key` index
A3.set_index('key').join([B2, C2], how='inner')

       valueA    valueB  valueC
key                            
D    1.454274 -0.977278     1.0
D    0.761038 -0.977278     1.0
62 eliu Apr 26 2019 at 06:43

Tampilan visual tambahan dari pd.concat([df0, df1], kwargs). Perhatikan bahwa, kwarg axis=0or axis=1's artinya tidak seintuitif df.mean()ataudf.apply(func)


5 GonçaloPeres龚燿禄 Aug 10 2020 at 17:13

Dalam jawaban ini, saya akan mempertimbangkan contoh praktis dari pandas.concat.

Mempertimbangkan hal berikut DataFramesdengan nama kolom yang sama:

Preco2018 dengan ukuran (8784, 5)

Preco 2019 dengan ukuran (8760, 5)

Itu memiliki nama kolom yang sama.

Anda dapat menggabungkannya menggunakan pandas.concat, dengan sederhana

import pandas as pd

frames = [Preco2018, Preco2019]

df_merged = pd.concat(frames)

Yang menghasilkan DataFrame dengan ukuran berikut (17544, 5)

Jika Anda ingin memvisualisasikan, akhirnya berfungsi seperti ini

( Sumber )