โพสต์นี้มีวัตถุประสงค์เพื่อให้ผู้อ่านได้รับข้อมูลเบื้องต้นเกี่ยวกับการผสาน SQL-flavored กับแพนด้า, วิธีใช้และเมื่อไม่ใช้
โดยเฉพาะอย่างยิ่งนี่คือสิ่งที่โพสต์นี้จะผ่าน:
สิ่งที่โพสต์นี้จะไม่ผ่าน:
- การสนทนาและการกำหนดเวลาที่เกี่ยวข้องกับประสิทธิภาพ (ตอนนี้) ส่วนใหญ่กล่าวถึงทางเลือกที่ดีกว่าตามความเหมาะสม
- การจัดการคำต่อท้ายการลบคอลัมน์พิเศษการเปลี่ยนชื่อเอาต์พุตและกรณีการใช้งานเฉพาะอื่น ๆ มีโพสต์อื่น ๆ (อ่าน: ดีกว่า) ที่จัดการกับมันดังนั้นลองคิดดูสิ!
หมายเหตุ
ตัวอย่างส่วนใหญ่จะเป็นค่าเริ่มต้นของการดำเนินการ INNER JOIN ในขณะที่แสดงคุณสมบัติต่าง ๆ เว้นแต่จะระบุไว้เป็นอย่างอื่น
นอกจากนี้ DataFrames ทั้งหมดที่นี่สามารถคัดลอกและทำซ้ำเพื่อให้คุณสามารถเล่นกับพวกเขาได้ ดูโพสต์นี้
เกี่ยวกับวิธีอ่าน DataFrames จากคลิปบอร์ดของคุณ
สุดท้ายการแสดงภาพการดำเนินการทั้งหมดของ JOIN นั้นถูกวาดด้วยมือโดยใช้ Google Drawings แรงบันดาลใจจากที่นี่
พอคุยแค่แสดงวิธีใช้merge
!
ติดตั้ง
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
เพื่อความเรียบง่ายคอลัมน์คีย์จึงมีชื่อเหมือนกัน (ตอนนี้)
INNER JOINเป็นตัวแทนจาก
หมายเหตุ
สิ่งนี้รวมถึงตัวเลขที่กำลังจะมาถึงเป็นไปตามอนุสัญญานี้:
- สีน้ำเงินหมายถึงแถวที่มีอยู่ในผลลัพธ์การผสาน
- สีแดงหมายถึงแถวที่ถูกแยกออกจากผลลัพธ์ (เช่นถูกลบ)
- สีเขียวหมายถึงค่าที่หายไปที่ถูกแทนที่ด้วย NaNs ในผลลัพธ์
หากต้องการดำเนินการ INNER JOIN ให้โทรmerge
ทางด้านซ้าย DataFrame โดยระบุ DataFrame ที่ถูกต้องและคีย์การเข้าร่วม (อย่างน้อยที่สุด) เป็นอาร์กิวเมนต์
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
ส่งกลับเฉพาะแถวจากleft
และright
ที่ใช้คีย์ร่วมกัน (ในตัวอย่างนี้ "B" และ "D)
ซ้าย OUTER JOINหรือ LEFT JOIN เป็นตัวแทนจาก
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 อย่างระมัดระวังที่นี่ หากคุณระบุจะใช้how='left'
เฉพาะคีย์จากleft
นั้นข้อมูลที่หายไปright
จะถูกแทนที่ด้วย NaN
และในทำนองเดียวกันสำหรับRIGHT OUTER JOINหรือ RIGHT JOIN ซึ่ง ...
... ระบุ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
ที่นี่right
มีการใช้คีย์จากและข้อมูลที่หายไปleft
ถูกแทนที่ด้วย NaN
ในที่สุดสำหรับเข้าร่วมเต็มที่ได้รับจาก
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
ใช้คีย์จากทั้งเฟรมและใส่ NaN สำหรับแถวที่ขาดหายไปในทั้งสอง
เอกสารสรุปการควบรวมกิจการต่าง ๆ เหล่านี้อย่าง:
การเข้าร่วมอื่น ๆ - การยกเว้นด้านซ้าย, การยกเว้นด้านขวา, และการยกเว้นแบบเต็ม / ANTI JOIN
หากคุณต้องการซ้ายไม่รวมร่วมและRIGHT-รวมร่วมในสองขั้นตอน
สำหรับการเข้าร่วมที่ไม่รวมซ้ายแสดงเป็น
เริ่มต้นด้วยการดำเนินการ LEFT OUTER JOIN แล้วกรอง (ยกเว้น!) แถวที่มาจากleft
เท่านั้น
(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
ที่ไหน
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
และในทำนองเดียวกันสำหรับการเข้าร่วมที่ถูกต้องไม่รวม
(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
สุดท้ายถ้าคุณต้องทำการผสานที่จะเก็บคีย์จากทางซ้ายหรือขวาเท่านั้น แต่ไม่ใช่ทั้งสองอย่าง (IOW, ทำการANTI-JOIN )
คุณสามารถทำได้ในแบบเดียวกัน -
(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
ชื่อที่แตกต่างกันสำหรับคอลัมน์สำคัญ
หากคอลัมน์หลักมีชื่อต่างกันตัวอย่างเช่นleft
มีkeyLeft
และright
มีkeyRight
แทนkey
- จากนั้นคุณจะต้องระบุleft_on
และใช้right_on
เป็นอาร์กิวเมนต์แทน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
หลีกเลี่ยงคอลัมน์คีย์ที่ซ้ำกันในเอาต์พุต
เมื่อทำการผสานkeyLeft
จากleft
และkeyRight
จากright
หากคุณต้องการอย่างใดอย่างหนึ่งkeyLeft
หรือkeyRight
(แต่ไม่ใช่ทั้งสองอย่าง) ในผลลัพธ์คุณสามารถเริ่มต้นด้วยการตั้งค่าดัชนีเป็นขั้นตอนเบื้องต้น
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
ตรงกันข้ามสิ่งนี้กับผลลัพธ์ของคำสั่งก่อนหน้า (นั่นคือผลลัพธ์ของleft2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')
) คุณจะสังเกตเห็นkeyLeft
หายไป คุณสามารถคิดได้ว่าจะให้คอลัมน์ใดอยู่บนพื้นฐานของดัชนีเฟรมที่ตั้งเป็นคีย์ เรื่องนี้อาจมีความสำคัญเมื่อพูดดำเนินการด้านนอกบางอย่างเข้าร่วม
การรวมเพียงหนึ่งคอลัมน์จากหนึ่งใน DataFrames
ตัวอย่างเช่นพิจารณา
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
หากคุณต้องการผสานเฉพาะ "new_val" (โดยไม่ต้องมีคอลัมน์อื่น ๆ ) โดยทั่วไปคุณสามารถเพียงแค่คอลัมน์ย่อยก่อนที่จะรวม:
left.merge(right3[['key', 'newcol']], on='key')
key value newcol
0 B 0.400157 0
1 D 2.240893 1
หากคุณกำลังทำ LEFT OUTER JOIN วิธีแก้ปัญหาที่มีประสิทธิภาพมากขึ้นจะเกี่ยวข้องกับ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
ดังที่กล่าวมานี้คล้ายกับ แต่เร็วกว่า
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
ผสานกับหลายคอลัมน์
หากต้องการเข้าร่วมมากกว่าหนึ่งคอลัมน์ให้ระบุรายการสำหรับon
(หรือleft_on
และright_on
ตามความเหมาะสม)
left.merge(right, on=['key1', 'key2'] ...)
หรือในกรณีที่ชื่อแตกต่างกัน
left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])
merge*
ปฏิบัติการและฟังก์ชั่นที่มีประโยชน์อื่น ๆ
ในส่วนนี้จะอธิบายพื้นฐานเบื้องต้นเท่านั้นและได้รับการออกแบบมาเพื่อกระตุ้นความอยากอาหารของคุณเท่านั้น สำหรับตัวอย่างเพิ่มเติมและกรณีให้ดูเอกสารเกี่ยวกับmerge
, join
และconcat
เช่นเดียวกับการเชื่อมโยงไปยังรายละเอียดฟังก์ชั่น
ดัชนีตาม * -JOIN (+ ดัชนีคอลัมน์merge
)
ติดตั้ง
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
โดยทั่วไปการผสานกับดัชนีจะมีลักษณะเช่นนี้:
left.merge(right, left_index=True, right_index=True)
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
รองรับชื่อดัชนี
หากดัชนีของคุณมีชื่อว่าผู้ใช้ v0.23 ยังสามารถระบุชื่อระดับเป็นon
(หรือleft_on
และright_on
ตามความจำเป็น)
left.merge(right, on='idxkey')
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
การผสานกับดัชนีของหนึ่งคอลัมน์ของอีกคอลัมน์หนึ่ง
เป็นไปได้ (และค่อนข้างง่าย) ในการใช้ดัชนีของหนึ่งและคอลัมน์ของอื่นเพื่อทำการผสาน ตัวอย่างเช่น,
left.merge(right, left_on='key1', right_index=True)
หรือในทางกลับกัน ( right_on=...
และ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
ในกรณีพิเศษนี้ดัชนีสำหรับleft
มีชื่อดังนั้นคุณสามารถใช้ชื่อดัชนีด้วย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
นอกจากนี้ยังมีตัวเลือกอื่นที่กระชับ คุณสามารถใช้DataFrame.join
ค่าเริ่มต้นที่จะเข้าร่วมกับดัชนี DataFrame.join
ค่าเริ่มต้นซ้ายเข้าร่วมโดยค่าเริ่มต้นจึงhow='inner'
จำเป็นที่นี่
left.join(right, how='inner', lsuffix='_x', rsuffix='_y')
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
โปรดทราบว่าฉันต้องระบุlsuffix
และrsuffix
ข้อโต้แย้งตั้งแต่join
มิฉะนั้นจะผิดพลาด:
left.join(right)
ValueError: columns overlap but no suffix specified: Index(['value'], dtype='object')
เนื่องจากชื่อคอลัมน์เหมือนกัน สิ่งนี้จะไม่เป็นปัญหาหากมีการตั้งชื่อต่างกัน
left.rename(columns={'value':'leftvalue'}).join(right, how='inner')
leftvalue value
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
pd.concat
สุดท้ายคุณสามารถใช้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'
ถ้าคุณต้องการเข้าร่วมเต็มรูปแบบภายนอก (ค่าเริ่มต้น):
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
สำหรับข้อมูลเพิ่มเติมโปรดดูที่โพสต์บัญญัตินี้pd.concat
โดย @piRSquared
การสรุป: รวมmerge
หลาย DataFrames
บ่อยครั้งที่สถานการณ์เกิดขึ้นเมื่อ DataFrames หลายรายการถูกรวมเข้าด้วยกัน อย่างไร้เดียงสาสิ่งนี้สามารถทำได้โดยการผูกmerge
สาย:
df1.merge(df2, ...).merge(df3, ...)
อย่างไรก็ตามสิ่งนี้ได้รับการพัฒนาอย่างรวดเร็วสำหรับ DataFrames มากมาย นอกจากนี้อาจจำเป็นต้องพูดคุยทั่วไปสำหรับ DataFrames ที่ไม่ทราบจำนวน
ที่นี่ฉันแนะนำpd.concat
สำหรับการรวมหลายทางในคีย์ที่ไม่ซ้ำกันและDataFrame.join
สำหรับการรวมหลายทางในคีย์ที่ไม่ซ้ำกัน ก่อนการตั้งค่า
# 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]
ผสานหลายทางบนคีย์เฉพาะ (หรือดัชนี)
ถ้าคีย์ของคุณ (ที่นี่ที่สำคัญอย่างใดอย่างหนึ่งอาจจะเป็นคอลัมน์หรือดัชนี) pd.concat
จะไม่ซ้ำกันแล้วคุณสามารถใช้ โปรดทราบว่าpd.concat
ร่วม DataFrames ดัชนี
# 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
ละเว้นjoin='inner'
การเข้าร่วมเต็มที่ โปรดทราบว่าคุณไม่สามารถระบุ LEFT หรือ RIGHT OUTER JOINS ได้ (หากคุณต้องการใช้งานjoin
ให้อธิบายด้านล่าง)
ผสานหลายปุ่มไว้ด้วยกัน
concat
รวดเร็ว แต่มีข้อบกพร่อง ไม่สามารถจัดการรายการซ้ำได้
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)
ในสถานการณ์นี้เราสามารถใช้join
เนื่องจากสามารถจัดการกับคีย์ที่ไม่ซ้ำกัน (โปรดทราบว่าjoin
รวม DataFrames ในดัชนีของพวกเขามันเรียกmerge
ภายใต้ประทุนและทำซ้ายเข้าร่วมนอกเว้นแต่ระบุไว้เป็นอย่างอื่น)
# 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