รับสอง dataframes ดังนี้:
>>> import pandas as pd
>>> df_a = pd.DataFrame([{"a": 1, "b": 4}, {"a": 2, "b": 5}, {"a": 3, "b": 6}])
>>> df_b = pd.DataFrame([{"c": 2, "d": 7}, {"c": 3, "d": 8}])
>>> df_a
a b
0 1 4
1 2 5
2 3 6
>>> df_b
c d
0 2 7
1 3 8
เราต้องการสร้างการรวมสไตล์ SQL ของ dataframe ทั้งสองโดยใช้เกณฑ์ที่ไม่ง่าย สมมติว่า "df_b.c > df_a.a" จากสิ่งที่ฉันบอกได้ แม้ว่า merge()
จะเป็นส่วนหนึ่งของโซลูชันอย่างแน่นอน แต่ฉันไม่สามารถใช้โดยตรงได้เนื่องจากไม่ยอมรับนิพจน์ที่กำหนดเองสำหรับเกณฑ์ "เปิด" (เว้นแต่ว่าฉันจะพลาดอะไรบางอย่างไป)
ใน SQL ผลลัพธ์จะมีลักษณะดังนี้:
# inner join
sqlite> select * from df_a join df_b on c > a;
1|4|2|7
1|4|3|8
2|5|3|8
# outer join
sqlite> select * from df_a left outer join df_b on c > a;
1|4|2|7
1|4|3|8
2|5|3|8
3|6||
แนวทางปัจจุบันของฉันสำหรับการรวมภายในคือการสร้างผลคูณคาร์ทีเซียนของ df_a และ df_b โดยเพิ่มคอลัมน์ "1" ให้กับทั้งคู่ จากนั้นใช้การผสาน () ในคอลัมน์ "1" จากนั้นใช้ "c > a" เกณฑ์.
>>> import numpy as np
>>> df_a['ones'] = np.ones(3)
>>> df_b['ones'] = np.ones(2)
>>> cartesian = pd.merge(df_a, df_b, left_on='ones', right_on='ones')
>>> cartesian
a b ones c d
0 1 4 1 2 7
1 1 4 1 3 8
2 2 5 1 2 7
3 2 5 1 3 8
4 3 6 1 2 7
5 3 6 1 3 8
>>> cartesian[cartesian.c > cartesian.a]
a b ones c d
0 1 4 1 2 7
1 1 4 1 3 8
3 2 5 1 3 8
สำหรับการเข้าร่วมภายนอก ฉันไม่แน่ใจถึงวิธีที่ดีที่สุด จนถึงตอนนี้ฉันเล่นกับการเข้าร่วมภายใน จากนั้นใช้การปฏิเสธเกณฑ์เพื่อรับแถวอื่น ๆ ทั้งหมด จากนั้นพยายามแก้ไข "การปฏิเสธนั้น "ตั้งไว้ที่เดิมแต่มันไม่ได้ผลจริงๆ
แก้ไข HYRY ตอบคำถามเฉพาะเจาะจงที่นี่ แต่ฉันต้องการบางสิ่งที่กว้างกว่าและมากกว่านั้นใน Pandas API เนื่องจากเกณฑ์การเข้าร่วมของฉันอาจเป็นอะไรก็ได้ ไม่ใช่แค่การเปรียบเทียบเพียงอย่างเดียว สำหรับ outerjoin ก่อนอื่นฉันจะเพิ่มดัชนีพิเศษที่ด้าน "ซ้าย" ซึ่งจะคงตัวเองไว้หลังจากที่ฉันเข้าร่วมภายใน:
df_a['_left_index'] = df_a.index
จากนั้นเราก็ทำคาร์ทีเซียนและเข้าร่วมภายใน:
cartesian = pd.merge(df_a, df_b, left_on='ones', right_on='ones')
innerjoin = cartesian[cartesian.c > cartesian.a]
จากนั้นฉันจะได้รับรหัสดัชนีเพิ่มเติมใน "df_a" ที่เราต้องการ และรับแถวจาก "df_a":
remaining_left_ids = set(df_a['_left_index']).\
difference(innerjoin['_left_index'])
remaining = df_a.ix[remaining_left_ids]
จากนั้นเราใช้ concat() แบบตรงซึ่งแทนที่คอลัมน์ที่หายไปด้วย "NaN" ทางซ้าย (ฉันคิดว่ามันไม่ได้ทำสิ่งนี้ก่อนหน้านี้ แต่ฉันเดาว่ามันเป็นเช่นนั้น):
outerjoin = pd.concat([innerjoin, remaining]).reset_index()
ความคิดของ HYRY ในการทำคาร์ทีเซียนกับคอลัมน์ที่เราจำเป็นต้องเปรียบเทียบนั้นเป็นคำตอบที่ถูกต้อง แม้ว่าในกรณีเฉพาะของฉัน อาจจะยุ่งยากเล็กน้อยในการนำไปใช้ (แบบทั่วไปและทั้งหมด)
คำถาม:
คุณจะสร้าง "เข้าร่วม" ของ df_1 และ df_2 บน "c > a" ได้อย่างไร คุณจะใช้แนวทาง "ผลิตภัณฑ์คาร์ทีเซียนตัวกรอง" แบบเดียวกันหรือมีวิธีที่ดีกว่านี้หรือไม่
คุณจะสร้าง "การรวมภายนอกด้านซ้าย" ของสิ่งเดียวกันได้อย่างไร