อะไรคือความแตกต่างระหว่างการเข้าร่วมและรวมใน Pandas?


208

สมมติว่าฉันมี DataFrames สองตัวดังนี้:

left = pd.DataFrame({'key1': ['foo', 'bar'], 'lval': [1, 2]})

right = pd.DataFrame({'key2': ['foo', 'bar'], 'rval': [4, 5]})

ฉันต้องการรวมพวกเขาดังนั้นฉันลองแบบนี้:

pd.merge(left, right, left_on='key1', right_on='key2')

และฉันมีความสุข

    key1    lval    key2    rval
0   foo     1       foo     4
1   bar     2       bar     5

แต่ฉันพยายามใช้วิธีการเข้าร่วมซึ่งฉันเชื่อว่ามันคล้ายกันมาก

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

และฉันได้รับสิ่งนี้:

//anaconda/lib/python2.7/site-packages/pandas/tools/merge.pyc in _validate_specification(self)
    406             if self.right_index:
    407                 if not ((len(self.left_on) == self.right.index.nlevels)):
--> 408                     raise AssertionError()
    409                 self.right_on = [None] * n
    410         elif self.right_on is not None:

AssertionError: 

ฉันกำลังคิดถึงอะไร


4
ปัญหาเฉพาะที่นี่คือการmergeรวมคอลัมน์ของleftไปยังคอลัมน์ของrightซึ่งเป็นสิ่งที่คุณต้องการ แต่join(... on=[...])รวมคอลัมน์ของleftไปยังคีย์ดัชนีของrightซึ่งไม่ใช่สิ่งที่คุณต้องการ ดูคำตอบของฉันด้านล่างสำหรับรายละเอียดเพิ่มเติม
Matthias Fripp

3
DataFrame.join () ต้องการจับคู่ดัชนีหรือคีย์ของผู้โทร (ระบุโดยonตัวเลือก) เสมอกับotherดัชนีของ จำไว้ว่าดัชนีสำหรับการเข้าร่วม ในขณะที่ผสาน () เป็นวิธีการทั่วไปมากขึ้น
Jiapeng Zhang

คำตอบ:


87

ฉันมักจะใช้joinกับดัชนี:

import pandas as pd
left = pd.DataFrame({'key': ['foo', 'bar'], 'val': [1, 2]}).set_index('key')
right = pd.DataFrame({'key': ['foo', 'bar'], 'val': [4, 5]}).set_index('key')
left.join(right, lsuffix='_l', rsuffix='_r')

     val_l  val_r
key            
foo      1      4
bar      2      5

สามารถใช้ฟังก์ชันการทำงานเดียวกันได้โดยใช้mergeในคอลัมน์ดังนี้:

left = pd.DataFrame({'key': ['foo', 'bar'], 'val': [1, 2]})
right = pd.DataFrame({'key': ['foo', 'bar'], 'val': [4, 5]})
left.merge(right, on=('key'), suffixes=('_l', '_r'))

   key  val_l  val_r
0  foo      1      4
1  bar      2      5

ข้อผิดพลาดที่ดูเหมือนว่าจะบอกว่ามันคาดว่าดัชนีหลายในที่มีความลึกเช่นเดียวกับระยะเวลาในright onนั่นทำให้ฉันรู้สึกว่า ฉันยอมรับได้ว่าความหมายต่างกัน แต่ฉันต้องการทราบว่าฉันสามารถใช้พฤติกรรมเดียวกันนี้กับ df.join
munk

346

pandas.merge() เป็นฟังก์ชันพื้นฐานที่ใช้สำหรับพฤติกรรมการรวม / เข้าร่วมทั้งหมด

DataFrames ให้pandas.DataFrame.merge()และวิธีการเป็นวิธีที่สะดวกในการเข้าถึงความสามารถของpandas.DataFrame.join() pandas.merge()ตัวอย่างเช่นdf1.merge(right=df2, ...)เทียบเท่าpandas.merge(left=df1, right=df2, ...)เทียบเท่ากับ

นี่คือความแตกต่างที่สำคัญระหว่างdf.join()และdf.merge():

  1. ค้นหาบนตารางที่ถูกต้อง: df1.join(df2)เข้าร่วมผ่านดัชนีของdf2เสมอ แต่df1.merge(df2)สามารถเข้าร่วมหนึ่งคอลัมน์หรือมากกว่าของdf2(ค่าเริ่มต้น) หรือไปที่ดัชนีของdf2(พร้อมright_index=True)
  2. ค้นหาบนโต๊ะด้านซ้าย: โดยค่าเริ่มต้นdf1.join(df2)ใช้ดัชนีของdf1และdf1.merge(df2)ใช้คอลัมน์ (s) df1ของ ที่สามารถจะถูกแทนที่โดยการระบุหรือdf1.join(df2, on=key_or_keys)df1.merge(df2, left_index=True)
  3. left vs inner join: df1.join(df2)ทำการรวมด้านซ้ายโดยค่าเริ่มต้น (เก็บแถวทั้งหมดไว้df1) แต่df.mergeเข้าร่วมแบบ Inner โดยค่าเริ่มต้น (ส่งกลับเฉพาะแถวที่ตรงกันdf1และdf2)

ดังนั้นวิธีการทั่วไปคือการใช้หรือpandas.merge(df1, df2) df1.merge(df2)แต่สำหรับสถานการณ์ทั่วไปจำนวนหนึ่ง (เก็บทุกแถวdf1และเข้าร่วมกับดัชนีในdf2) คุณสามารถบันทึกการพิมพ์โดยใช้df1.join(df2)แทน

บันทึกบางส่วนในประเด็นเหล่านี้จากเอกสารที่http://pandas.pydata.org/pandas-docs/stable/merging.html#database-style-dataframe-joining-merging :

merge เป็นฟังก์ชั่นในเนมสเปซแพนด้าและมันก็ยังเป็นวิธีการอินสแตนซ์ DataFrame ด้วยการเรียก DataFrame โดยปริยายถือว่าเป็นวัตถุด้านซ้ายในการเข้าร่วม

DataFrame.joinวิธีการที่เกี่ยวข้องใช้mergeภายในสำหรับการรวมดัชนีกับดัชนีและดัชนีบนคอลัมน์ แต่เข้าร่วมกับดัชนีโดยค่าเริ่มต้นแทนที่จะพยายามเข้าร่วมในคอลัมน์ทั่วไป (พฤติกรรมเริ่มต้นสำหรับmerge) หากคุณเข้าร่วมกับดัชนีคุณอาจต้องการใช้DataFrame.joinเพื่อช่วยให้คุณพิมพ์ด้วยตัวเอง

...

การเรียกใช้ฟังก์ชันทั้งสองนี้เทียบเท่ากันอย่างสมบูรณ์:

left.join(right, on=key_or_keys)
pd.merge(left, right, left_on=key_or_keys, right_index=True, how='left', sort=False)

19
นี่ควรเป็นคำตอบที่ได้รับการยอมรับอย่างแน่นอน! ขอบคุณสำหรับคำอธิบายของคุณ
Yohan Obadia

@Matthias ปป์อาจจะเป็นเพราะมีประสบการณ์มากขึ้นก็ไปโดยไม่บอก แต่มันก็อาจจะกล่าวได้ว่า "การค้นหาบนโต๊ะขวา:? df1.join (df2) สามารถแทนที่การ df1.join (df2 บน = key_or_keys
spacedustpi

@spustustpi ฉันคิดว่าคุณกำลังบอกว่าคุณสามารถใช้on=key_or_keysเพื่อเปลี่ยนวิธีการค้นพบแถวในตารางด้านขวา อย่างไรก็ตามนั่นไม่ใช่กรณีจริง onอาร์กิวเมนต์เปลี่ยนแปลงการค้นหาบนซ้ายตาราง ( df1) จากดัชนีคอลัมน์ (s) อย่างไรก็ตามแม้จะมีอาร์กิวเมนต์นี้ตารางด้านขวา ( df2) จะถูกจับคู่ผ่านดัชนี (ดูตัวอย่างล่าสุดด้านบน)
Matthias Fripp

Pandas มีวิธีการหลายวิธีในการจัดการกับสถานการณ์เหล่านี้ในหมู่พวกเขารวมเข้าร่วมผนวกผนวกรวมกันรวมแรก ลองดูที่แต่ละสิ่งเหล่านี้เพื่อดูว่าใครจะเหมาะกับสถานการณ์ของคุณมากที่สุด
xiaxio

13

ฉันเชื่อว่าjoin()เป็นเพียงวิธีการอำนวยความสะดวก ลองdf1.merge(df2)แทนซึ่งช่วยให้คุณระบุleft_onและright_on:

In [30]: left.merge(right, left_on="key1", right_on="key2")
Out[30]: 
  key1  lval key2  rval
0  foo     1  foo     4
1  bar     2  bar     5

11

จากเอกสารนี้

pandas จัดเตรียมฟังก์ชันเดี่ยวผสานเป็นจุดเริ่มต้นสำหรับการดำเนินการเข้าร่วมฐานข้อมูลมาตรฐานทั้งหมดระหว่างวัตถุ DataFrame:

merge(left, right, how='inner', on=None, left_on=None, right_on=None,
      left_index=False, right_index=False, sort=True,
      suffixes=('_x', '_y'), copy=True, indicator=False)

และ:

DataFrame.joinเป็นวิธีที่สะดวกในการรวมคอลัมน์ของ DataFrames สองดัชนีที่อาจแตกต่างกันเป็น DataFrame ผลลัพธ์เดียว นี่คือตัวอย่างพื้นฐานมาก: การจัดแนวข้อมูลที่นี่อยู่บนดัชนี (เลเบลแถว) พฤติกรรมเดียวกันนี้สามารถทำได้โดยใช้การผสานรวมทั้งข้อโต้แย้งเพิ่มเติมที่แนะนำให้ใช้ดัชนี:

result = pd.merge(left, right, left_index=True, right_index=True,
how='outer')

8

หนึ่งในความแตกต่างคือmergeการสร้างดัชนีใหม่และjoinรักษาดัชนีด้านซ้าย mergeมันจะมีผลอย่างมากต่อการเปลี่ยนแปลงในภายหลังของคุณถ้าคุณผิดคิดว่าดัชนีของคุณจะไม่เปลี่ยนแปลงด้วย

ตัวอย่างเช่น:

import pandas as pd

df1 = pd.DataFrame({'org_index': [101, 102, 103, 104],
                    'date': [201801, 201801, 201802, 201802],
                    'val': [1, 2, 3, 4]}, index=[101, 102, 103, 104])
df1

       date  org_index  val
101  201801        101    1
102  201801        102    2
103  201802        103    3
104  201802        104    4

-

df2 = pd.DataFrame({'date': [201801, 201802], 'dateval': ['A', 'B']}).set_index('date')
df2

       dateval
date          
201801       A
201802       B

-

df1.merge(df2, on='date')

     date  org_index  val dateval
0  201801        101    1       A
1  201801        102    2       A
2  201802        103    3       B
3  201802        104    4       B

-

df1.join(df2, on='date')
       date  org_index  val dateval
101  201801        101    1       A
102  201801        102    2       A
103  201802        103    3       B
104  201802        104    4       B

ถูกต้อง. ถ้าเรารวมสองเฟรมข้อมูลในคอลัมน์อื่นที่ไม่ใช่ดัชนีเราจะได้รับดัชนีใหม่ แต่ถ้าเรารวมกับดัชนีของเฟรมข้อมูลทั้งสองเราจะได้รับเฟรมข้อมูลที่มีดัชนีเดียวกัน ดังนั้นเพื่อให้ได้ดัชนีเดียวกันหลังจากผสานเราสามารถสร้างคอลัมน์ดัชนีของเรา (ที่เราต้องการผสาน) สำหรับทั้งเฟรมข้อมูลแล้วรวมเฟรมข้อมูลในดัชนีที่สร้างขึ้นใหม่
hasan najeeb

ลึกซึ้งมาก ฉันไม่เคยต้องการการทำดัชนี (โดยปกติฉันเพิ่งรีเซ็ตดัชนี) แต่สิ่งนี้อาจสร้างความแตกต่างอย่างมากในบางกรณี
irene

4
  • เข้าร่วม: ดัชนีเริ่มต้น (หากชื่อคอลัมน์เดียวกันแล้วมันจะโยนข้อผิดพลาดในโหมดเริ่มต้นเพราะคุณยังไม่ได้กำหนด lsuffix หรือ rsuffix)
df_1.join(df_2)
  • ผสาน: ชื่อคอลัมน์เริ่มต้นที่เหมือนกัน (หากไม่มีชื่อคอลัมน์เดียวกันจะทำให้เกิดข้อผิดพลาดในโหมดเริ่มต้น)
df_1.merge(df_2)
  • on พารามิเตอร์มีความหมายแตกต่างกันในทั้งสองกรณี
df_1.merge(df_2, on='column_1')

df_1.join(df_2, on='column_1') // It will throw error
df_1.join(df_2.set_index('column_1'), on='column_1')

2

เมื่อต้องการวางแบบอะนาล็อกกับ SQL "Pandas merge คือการรวมภายนอก / ภายในและการรวม Pandas เป็นการรวมธรรมชาติ" ดังนั้นเมื่อคุณใช้การรวมเป็นแพนด้าคุณต้องการระบุชนิดของการเข้าร่วมแบบ sqlish ที่คุณต้องการใช้ในขณะที่เมื่อคุณใช้การรวมแบบ pandas คุณต้องมีป้ายชื่อคอลัมน์ที่ตรงกันเพื่อให้แน่ใจว่ามันเข้าร่วม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.