Pandalar Birleştirme 101


366
  • Pandalarla bir ( LEFT| RIGHT| FULL) ( INNER| OUTER) birleştirmesi nasıl yapılır ?
  • Birleştirme işleminden sonra eksik satırlar için NaN'leri nasıl eklerim?
  • Birleştirdikten sonra NaN'lerden nasıl kurtulurum?
  • Dizinde birleştirebilir miyim?
  • Pandalar ile çapraz katılmak?
  • Birden çok DataFrame'i nasıl birleştiririm?
  • merge? join? concat? update? DSÖ? Ne? Neden?!

... ve dahası. Pandaların birleştirme işlevinin çeşitli yönlerini soran bu tekrarlayan soruları gördüm. Birleştirme ve bugünkü çeşitli kullanım durumlarıyla ilgili bilgilerin çoğu, düzinelerce kötü ifade edilmiş, araştırılamayan gönderi arasında bölünmüştür. Burada amaç, gelecek nesiller için daha önemli noktalardan bazılarını bir araya getirmektir.

Bu QnA, ortak panda deyimlerinde bir dizi yararlı kullanıcı kılavuzunda bir sonraki taksit olması anlamına geliyor ( pivotlama üzerine bu gönderi ve daha sonra değineceğim birleştirme hakkındaki bu gönderiye bakın ).

Bu yazı olduğunu not edin olmayan bir yedek olmak üzere belgelerin , böylece de okuyunuz! Bazı örnekler oradan alınmıştır.

Yanıtlar:


523

Bu yazı, okuyuculara pandalarla SQL aromalı birleştirme, nasıl kullanılacağı ve kullanılmadığı zaman bir astar vermeyi amaçlamaktadır.

Özellikle, bu yazının içinden geçecekler:

  • Temel bilgiler - birleştirme türleri (SOL, SAĞ, DIŞ, İÇ)

    • farklı sütun adlarıyla birleştirme
    • çıktıda yinelenen birleştirme anahtarı sütunundan kaçınma
  • Farklı koşullar altında dizinle birleştirme
    • adlandırılmış dizini etkili bir şekilde kullanma
    • birinin dizini ve diğerinin sütunu olarak birleştirme anahtarı
  • Sütunlar ve dizinlerde çok yönlü birleştirme (benzersiz ve benzersiz olmayan)
  • İçin Önemli alternatifleri mergevejoin

Bu yazı ne geçmeyecek:

  • Performansla ilgili tartışmalar ve zamanlamalar (şimdilik). Çoğunlukla dikkate değer, uygun olan yerlerde daha iyi alternatiflerden bahseder.
  • Son ekleri işleme, fazladan sütunları kaldırma, çıktıları yeniden adlandırma ve diğer özel kullanım durumları. Bununla ilgili başka (daha iyi: daha iyi) yayınlar var, bu yüzden anlayın!

Not
Aksi belirtilmedikçe, çoğu örnek varsayılan olarak çeşitli özellikleri gösterirken INNER JOIN işlemleri için varsayılan değerdir.

Ayrıca, buradaki tüm DataFrame'ler kopyalanabilir ve çoğaltılabilir, böylece onlarla oynayabilirsiniz. Ayrıca bakınız bu yazıyı panonuzdan DataFrames okumak için nasıl.

Son olarak, JOIN işlemlerinin tüm görsel gösterimleri Google Çizimler kullanılarak elle çizilmiştir. Buradan ilham alın .

Yeter Konuşma, nasıl kullanılacağını bana göster merge!

Kurmak

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

Kolaylık olması açısından, anahtar sütun aynı ada sahiptir (şimdilik).

Bir INNER JOIN ,

Not
Bu, gelecek rakamlarla birlikte bu sözleşmeyi takip eder:

  • mavi , birleştirme sonucunda bulunan satırları gösterir
  • kırmızı , sonuçtan hariç tutulan satırları belirtir (yani, kaldırılır)
  • yeşil , sonuçta NaN ile değiştirilen eksik değerleri gösterir

Bir INNER JOIN gerçekleştirmek için merge, sol DataFrame'i arayın , sağ DataFrame'i ve birleştirme anahtarını (en azından) bağımsız değişken olarak belirtin.

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

Bu döner gelen satırları leftve rightortak bir (bu örnekte, "B" ve "D) tuşuna paylaşır.

Bir sol dış birleşim veya SOL ile temsil edilir artır

Bu, belirtilerek yapılabilir 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

NaN'lerin buraya yerleştirildiğini dikkatlice not edin. Belirtirseniz how='left', yalnızca anahtarlar leftkullanılır ve eksik veriler rightNaN ile değiştirilir.

Ve benzer şekilde, bir DOĞRU DIŞ ORTAK veya SAĞ birleşim için ...

... belirtin 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

Burada, anahtarlar rightkullanılır ve eksik veriler leftNaN ile değiştirilir.

Son olarak, FULL OUTER JOIN için ,

belirtin 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

Bu, her iki karedeki anahtarları kullanır ve her iki satırdaki eksik satırlar için NaN'ler eklenir.

Belgeler bu çeşitli birleştirmeleri güzel bir şekilde özetlemektedir:

resim açıklamasını buraya girin

Diğer BAĞLANTILAR - SOL-Hariç, SAĞ-Hariç ve TAM Hariç / ANTI JOIN'ler

İki adımda SOL-HARİCİ JOIN'lara ve SAĞ- HARİCİ JOIN'lara ihtiyacınız varsa .

Olarak temsil edilen SOL-hariç JOIN için

Bir LEFT OUTER JOIN gerçekleştirerek ve leftyalnızca gelen satırları filtreleyerek (hariç!) ,

(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

Nerede,

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

Benzer şekilde, DOĞRU OLMAYAN BİR BİRLEŞME için,

(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

Son olarak, yalnızca soldan veya sağdan anahtarları tutan, ancak her ikisini birden olmayan bir birleştirme yapmanız gerekiyorsa (IOW, bir ANTI-JOIN gerçekleştirme ),

Bunu benzer şekilde yapabilirsiniz -

(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

Anahtar sütunlar için farklı adlar

Anahtar sütunlar farklı adlandırılırsa (örneğin, yerine) leftsahipse keyLeftve rightsahipse, keyRightbunun yerine keyaşağıdakileri belirtmeniz left_onve right_onbağımsız değişken olarak belirtmeniz gerekir 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

Çıktıda yinelenen anahtar sütunundan kaçınma

Üzerinde birleştirirken keyLeftgelen leftve keyRightgelen rightsadece birinin istiyorsanız keyLeftveya keyRightçıktıda (ama ikisini), bir ön adım olarak indeksini ayarlayarak başlayabilir.

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

Bunu komutun çıktısından hemen önce (bu çıktı, çıktısı ile left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')) karşılaştırın, keyLefteksik olduğunu fark edeceksiniz . Hangi karenin dizininin anahtar olarak ayarlandığına bağlı olarak hangi sütunun tutulacağını anlayabilirsiniz. Diyelim ki, bazı OUTER JOIN işlemlerinin yapılması önemli olabilir.

Yalnızca bir sütunu, DataFrames

Örneğin,

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

Yalnızca "new_val" değerini birleştirmeniz gerekiyorsa (diğer sütunlardan herhangi biri olmadan), birleştirmeden önce genellikle yalnızca sütunları alt kümeye ayarlayabilirsiniz:

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

  key     value  newcol
0   B  0.400157       0
1   D  2.240893       1

SOL DIŞ BİRLEŞME yapıyorsanız, daha performanslı bir çözüm mapşunları içerir :

# 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

Belirtildiği gibi, bu benzer, ancak daha hızlı

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

Birden çok sütunda birleştirme

Birden fazla sütun üzerinde katılmak için, bir listesini belirtin on(ya left_onve right_onuygun olanları).

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

Veya isimler farklıysa,

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

Diğer faydalı merge*işlemler ve fonksiyonlar

Bu bölüm sadece temel bilgileri içerir ve sadece iştahınızı hafifletmek için tasarlanmıştır. Daha fazla örnek ve durumlar için, bkz belgelerine merge, joinveconcat aynı zamanda fonksiyon özellikleri bağlantılar gibi.


Dizin tabanlı * -JOIN (+ dizin sütunları merge)

Kurmak

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

Tipik olarak, dizindeki birleştirme şöyle görünür:

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


         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Dizin adları için destek

İşaret adlı, o zaman v0.23 kullanıcıların da seviye adını belirtebilirsiniz on(veya left_onve right_ongerektiği gibi).

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

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Birinin dizininde, diğerinin sütunlarında birleştirme

Birleştirme gerçekleştirmek için birinin dizinini ve diğerinin sütununu kullanmak mümkündür (ve oldukça basittir). Örneğin,

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

Ya da tam tersi ( right_on=...ve 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

Bu özel durumda, dizini leftadlandırılır, böylece dizin adını şu şekilde de kullanabilirsiniz left_on:

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
Bunların yanında başka bir özlü seçenek daha var. DataFrame.joinDizinde birleştirilecek varsayılanları kullanabilirsiniz . DataFrame.joinvarsayılan olarak bir LEFT OUTER JOIN yapar, bu yüzden how='inner'burada gereklidir.

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

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Ben aksi takdirde hata olur lsuffixve rsuffixçünkü argümanlar belirtmek için gerekli olduğunu unutmayın join:

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

Sütun adları aynı olduğundan. Farklı isimlendirildikleri takdirde bu sorun olmaz.

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

        leftvalue     value
idxkey                     
B       -0.402655  0.543843
D       -0.524349  0.013135

pd.concat
Son olarak, dizin tabanlı birleşimlere alternatif olarak şunları kullanabilirsiniz 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

join='inner'TAM DIŞ BİRLEŞMEYE ihtiyacınız varsa atlayın (varsayılan):

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

Daha fazla bilgi için @piRSquared tarafından hazırlanan bu standart pd.concatgönderiye bakın .


Genelleme: mergebirden çok DataFrames oluşturma

Çoğu zaman, birden çok DataFrame'in bir araya getirilmesi durumunda bu durum ortaya çıkar. Safça, bu mergeçağrı zincirleme yoluyla yapılabilir :

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

Ancak, bu birçok DataFrame için çabucak kontrolden çıkar. Ayrıca, bilinmeyen sayıda DataFrame için genelleme yapmak gerekebilir.

Burada tanıtmak pd.concatçok yönlü katılıp için eşsiz anahtar ve DataFrame.joinçoklu yol üzerinde birleştiği benzersiz olmayan anahtarlar. İlk olarak, kurulum.

# 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]

Benzersiz anahtarlarda (veya dizinde) çok yönlü birleştirme

Anahtarlarınız (burada, anahtar bir sütun veya bir dizin olabilir) benzersizse, kullanabilirsiniz pd.concat. Not pd.concatendeksi DataFrames katılır .

# 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

Omit join='inner'tam dış için artır. SOL veya SAĞ DIŞ birleşimleri belirtemeyeceğinizi unutmayın (bunlara ihtiyacınız varsa join, aşağıda açıklananları kullanın ).

Yinelenen tuşlarda çok yönlü birleştirme

concathızlı, ama eksiklikleri var. Kopyaları işleyemez.

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)

Bu durumda, joinbenzersiz olmayan anahtarları işleyebildiği için kullanabiliriz ( joinDataFrames'ları dizinlerinde birleştirir; mergebaşlık altında çağırır ve aksi belirtilmedikçe bir SOL DIŞ birleşim yapar).

# 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

1
Bu muhtemelen şimdiye kadar görülen en iyi cevaptır.
Kathiravan Natarajan

@KathiravanNatarajan alışverişe devam et ... Nihayetinde daha iyi bir tane bulacaksınız ;-)
cs95

50

Tamamlayıcı bir görsel bakış pd.concat([df0, df1], kwargs). Dikkat edin, kwarg axis=0veya axis=1'nin anlamı df.mean()veya kadar sezgisel değildir.df.apply(func)


pd.concat üzerinde ([df0, df1])


9
Bu güzel bir diyagram. Nasıl ürettiğini sorabilir miyim?
cs95

6
google doc'ın yerleşik "insert ==> çizim ... ==> yeni" (2019-Mayıs itibarıyla). Ancak, açık olmak gerekirse: Bu resim için google doc kullanmamın tek nedeni, notlarımın google doc'da depolanması ve google doc'nin içinde hızlı bir şekilde değiştirilebilen bir resim istiyorum. Aslında bundan bahsettiniz, google doc'ın çizim aracı oldukça düzgün.
eliu

Vay canına, bu harika. SQL dünyasından gelen "dikey" birleştirme, tablonun yapısı her zaman sabit olduğundan kafamda bir birleşim değildir. Şimdi pandaların sağlamlaşmasını concatve mergebir yön parametresinin horizontalveya olması gerektiğini düşünün vertical.
Ufos

2
@Ufos tam olarak bu değil axis=1ve axis=0nedir?
cs95

2
evet, şimdi oradayız mergeve concatve eksen ve her neyse. Bununla birlikte, @eliu'nun gösterdiği gibi, bunların hepsi "sol" ve "sağ" ve "yatay" veya "dikey" ile birleştirme kavramıyla aynıdır . Ben, şahsen, dokümantasyon içine ben hangi "eksen" hatırlamak zorunda her zaman bakmak zorunda 0ve hangi 1.
Ufos
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.