ผลิตภัณฑ์คาร์ทีเซียนในหมีแพนด้า


109

ฉันมีดาต้าเฟรมของแพนด้าสองตัว:

from pandas import DataFrame
df1 = DataFrame({'col1':[1,2],'col2':[3,4]})
df2 = DataFrame({'col3':[5,6]})     

แนวทางปฏิบัติที่ดีที่สุดในการรับผลิตภัณฑ์คาร์ทีเซียนคืออะไร (แน่นอนว่าไม่ต้องเขียนให้ชัดเจนเหมือนฉัน)

#df1, df2 cartesian product
df_cartesian = DataFrame({'col1':[1,2,1,2],'col2':[3,4,3,4],'col3':[5,5,6,6]})

คำตอบ:


90

หากคุณมีคีย์ที่ซ้ำกันสำหรับแต่ละแถวคุณสามารถสร้างผลิตภัณฑ์คาร์ทีเซียนโดยใช้การผสาน (เช่นเดียวกับที่คุณทำใน SQL)

from pandas import DataFrame, merge
df1 = DataFrame({'key':[1,1], 'col1':[1,2],'col2':[3,4]})
df2 = DataFrame({'key':[1,1], 'col3':[5,6]})

merge(df1, df2,on='key')[['col1', 'col2', 'col3']]

เอาท์พุต:

   col1  col2  col3
0     1     3     5
1     1     3     6
2     2     4     5
3     2     4     6

ดูเอกสารที่นี่: http://pandas.pydata.org/pandas-docs/stable/merging.html#brief-primer-on-merge-methods-relational-algebra


7
ดังนั้นในการทำสิ่งนี้ให้ถูกต้องเราต้องหาชื่อคอลัมน์ที่ไม่ได้ใช้ก่อนจากนั้นเพิ่มคอลัมน์ดัมมี่ด้วยชื่อนั้นผสานและสุดท้ายวางคอลัมน์ลงในผลลัพธ์? ซึ่งตรงข้ามกับการอ่านข้อมูลที่มีหมีแพนด้าเป็นเพียงความเจ็บปวด
Bananach

69

ใช้pd.MultiIndex.from_productเป็นดัชนีในดาต้าเฟรมที่ว่างเปล่าจากนั้นรีเซ็ตดัชนีเท่านี้ก็เสร็จเรียบร้อย

a = [1, 2, 3]
b = ["a", "b", "c"]

index = pd.MultiIndex.from_product([a, b], names = ["a", "b"])

pd.DataFrame(index = index).reset_index()

ออก:

   a  b
0  1  a
1  1  b
2  1  c
3  2  a
4  2  b
5  2  c
6  3  a
7  3  b
8  3  c

6
ฉันเชื่อว่านี่เป็นวิธีที่เหมือนหมีแพนด้ามากที่สุดในทุกวันนี้สำหรับหมีแพนด้า> = 0.21
shai

7
คุณมีการโหวตลดลงเนื่องจากคุณไม่ได้แสดงให้เห็นว่าสิ่งนี้จะสรุปสำหรับสิ่งที่มีมากกว่า 1 คอลัมน์อย่างไร
cs95

ฟังก์ชั่นนี้ ( stackoverflow.com/a/58242079/1840471 ) สรุปให้เป็นจำนวนรายการโดยพลการโดยใช้คำสั่งของอาร์กิวเมนต์ มันแตกต่างจากคำถามที่นี่เล็กน้อยซึ่งใช้ผลิตภัณฑ์คาร์ทีเซียนของสอง DataFrames (กล่าวคือไม่ได้ใช้ผลิตภัณฑ์ของdf1.col1และdf.col2)
Max Ghenis

1
อันที่จริงฉันไม่คิดว่าfrom_productจะใช้กับปัญหานี้ได้
Max Ghenis

34

สิ่งนี้จะไม่ชนะการแข่งขันกอล์ฟรหัสและยืมจากคำตอบก่อนหน้านี้ - แต่จะแสดงให้เห็นอย่างชัดเจนว่ามีการเพิ่มคีย์อย่างไรและการเข้าร่วมทำงานอย่างไร ซึ่งจะสร้างกรอบข้อมูลใหม่ 2 เฟรมจากรายการจากนั้นเพิ่มคีย์เพื่อทำผลิตภัณฑ์คาร์ทีเซียน

กรณีการใช้งานของฉันคือฉันต้องการรายการรหัสร้านค้าทั้งหมดสำหรับแต่ละสัปดาห์ในรายการของฉัน ดังนั้นฉันจึงสร้างรายการของสัปดาห์ทั้งหมดที่ฉันต้องการจากนั้นก็คือรายชื่อของรหัสร้านค้าทั้งหมดที่ฉันต้องการจับคู่

การผสานที่ฉันเลือกไว้ทางซ้าย แต่จะมีความหมายเหมือนกับภายในในการตั้งค่านี้ คุณสามารถดูสิ่งนี้ได้ในเอกสารประกอบเกี่ยวกับการรวมซึ่งระบุว่าเป็นผลิตภัณฑ์คาร์ทีเซียนหากคีย์ผสมปรากฏมากกว่าหนึ่งครั้งในทั้งสองตารางซึ่งเป็นสิ่งที่เราตั้งขึ้น

days = pd.DataFrame({'date':list_of_days})
stores = pd.DataFrame({'store_id':list_of_stores})
stores['key'] = 0
days['key'] = 0
days_and_stores = days.merge(stores, how='left', on = 'key')
days_and_stores.drop('key',1, inplace=True)

25
รุ่นที่สั้นกว่าเล็กน้อย:days_and_stores = pd.merge(days.assign(key=0), stores.assign(key=0), on='key').drop('key', axis=1)
Eugene Pakhomov

คุณพูดถึง crossJoin แต่คุณกำลังใช้ดาต้าเฟรมของแพนด้าไม่ใช่ดาต้าเฟรมจุดประกาย
Bryce Guinta

แดง. ไม่ได้คิด ฉันใช้ spark + pandas ด้วยกันบ่อยมากจนเมื่อฉันเห็นการอัปเดตเพื่อจุดประกายฉันก็คิดถึงโพสต์นี้ ขอบคุณ Bryce
Rob Guderian

32

จำเป็นต้องใช้รหัสขั้นต่ำสำหรับรหัสนี้ สร้าง 'คีย์' ทั่วไปเพื่อรวมคาร์ทีเซียนทั้งสอง:

df1['key'] = 0
df2['key'] = 0

df_cartesian = df1.merge(df2, how='outer')

8
+ df_cartesian = df_cartesian.drop(columns=['key'])เพื่อทำความสะอาดในตอนท้าย
StackG


14

อีกทางเลือกหนึ่งคือเราสามารถพึ่งพาผลิตภัณฑ์คาร์ทีเซียนที่ itertools จัดหาให้: itertools.productซึ่งหลีกเลี่ยงการสร้างคีย์ชั่วคราวหรือแก้ไขดัชนี:

import numpy as np 
import pandas as pd 
import itertools

def cartesian(df1, df2):
    rows = itertools.product(df1.iterrows(), df2.iterrows())

    df = pd.DataFrame(left.append(right) for (_, left), (_, right) in rows)
    return df.reset_index(drop=True)

ทดสอบด่วน:

In [46]: a = pd.DataFrame(np.random.rand(5, 3), columns=["a", "b", "c"])

In [47]: b = pd.DataFrame(np.random.rand(5, 3), columns=["d", "e", "f"])    

In [48]: cartesian(a,b)
Out[48]:
           a         b         c         d         e         f
0   0.436480  0.068491  0.260292  0.991311  0.064167  0.715142
1   0.436480  0.068491  0.260292  0.101777  0.840464  0.760616
2   0.436480  0.068491  0.260292  0.655391  0.289537  0.391893
3   0.436480  0.068491  0.260292  0.383729  0.061811  0.773627
4   0.436480  0.068491  0.260292  0.575711  0.995151  0.804567
5   0.469578  0.052932  0.633394  0.991311  0.064167  0.715142
6   0.469578  0.052932  0.633394  0.101777  0.840464  0.760616
7   0.469578  0.052932  0.633394  0.655391  0.289537  0.391893
8   0.469578  0.052932  0.633394  0.383729  0.061811  0.773627
9   0.469578  0.052932  0.633394  0.575711  0.995151  0.804567
10  0.466813  0.224062  0.218994  0.991311  0.064167  0.715142
11  0.466813  0.224062  0.218994  0.101777  0.840464  0.760616
12  0.466813  0.224062  0.218994  0.655391  0.289537  0.391893
13  0.466813  0.224062  0.218994  0.383729  0.061811  0.773627
14  0.466813  0.224062  0.218994  0.575711  0.995151  0.804567
15  0.831365  0.273890  0.130410  0.991311  0.064167  0.715142
16  0.831365  0.273890  0.130410  0.101777  0.840464  0.760616
17  0.831365  0.273890  0.130410  0.655391  0.289537  0.391893
18  0.831365  0.273890  0.130410  0.383729  0.061811  0.773627
19  0.831365  0.273890  0.130410  0.575711  0.995151  0.804567
20  0.447640  0.848283  0.627224  0.991311  0.064167  0.715142
21  0.447640  0.848283  0.627224  0.101777  0.840464  0.760616
22  0.447640  0.848283  0.627224  0.655391  0.289537  0.391893
23  0.447640  0.848283  0.627224  0.383729  0.061811  0.773627
24  0.447640  0.848283  0.627224  0.575711  0.995151  0.804567

4
ฉันทดสอบแล้วและใช้งานได้ แต่ช้ากว่าคำตอบด้านบนสำหรับการผสานรวมสำหรับชุดข้อมูลขนาดใหญ่
MrJ

2

หากคุณไม่มีคอลัมน์ที่ทับซ้อนกันไม่ต้องการเพิ่มคอลัมน์และสามารถละทิ้งดัชนีของกรอบข้อมูลได้อาจทำได้ง่ายกว่า:

df1.index[:] = df2.index[:] = 0
df_cartesian = df1.join(df2, how='outer')
df_cartesian.index[:] = range(len(df_cartesian))

1
สิ่งนี้ดูมีแนวโน้ม - แต่ฉันได้รับข้อผิดพลาดในบรรทัดแรก: TypeError: '<class 'pandas.core.index.Int64Index'>' does not support mutable operations. ฉันสามารถแก้ไขปัญหานี้ได้โดยเพิ่ม, index=[0,0]คำจำกัดความของ dataframe
Racing Tadpole

2
หรือใช้df1 = df1.set_index([[0]*len(df1)]))(และในทำนองเดียวกันสำหรับdf2)
แข่งลูกอ๊อด

การแก้ไขของ Racing Tadpole ทำให้งานนี้สำหรับฉัน - ขอบคุณ!
Sevyns

2

นี่คือฟังก์ชั่นตัวช่วยในการดำเนินการผลิตภัณฑ์คาร์ทีเซียนอย่างง่ายด้วยกรอบข้อมูลสองเฟรม ตรรกะภายในจัดการโดยใช้คีย์ภายในและหลีกเลี่ยงการยุ่งเกี่ยวกับคอลัมน์ใด ๆ ที่มีชื่อว่า "คีย์" จากด้านใดด้านหนึ่ง

import pandas as pd

def cartesian(df1, df2):
    """Determine Cartesian product of two data frames."""
    key = 'key'
    while key in df1.columns or key in df2.columns:
        key = '_' + key
    key_d = {key: 0}
    return pd.merge(
        df1.assign(**key_d), df2.assign(**key_d), on=key).drop(key, axis=1)

# Two data frames, where the first happens to have a 'key' column
df1 = pd.DataFrame({'number':[1, 2], 'key':[3, 4]})
df2 = pd.DataFrame({'digit': [5, 6]})
cartesian(df1, df2)

การแสดง:

   number  key  digit
0       1    3      5
1       1    3      6
2       2    4      5
3       2    4      6

ใช้เวลาสองครั้งเมื่อฉันเห็นว่าคำถามอายุ 7 ขวบมีคำตอบ 4 ชั่วโมง - ขอบคุณมากสำหรับสิ่งนี้ :)
Bruno E

0

คุณสามารถเริ่มต้นโดยการใช้ผลิตภัณฑ์คาร์ทีเซียนdf1.col1และdf2.col3แล้วผสานกลับไปที่จะได้รับdf1col2

นี่คือฟังก์ชันผลิตภัณฑ์คาร์ทีเซียนทั่วไปซึ่งใช้พจนานุกรมรายการ:

def cartesian_product(d):
    index = pd.MultiIndex.from_product(d.values(), names=d.keys())
    return pd.DataFrame(index=index).reset_index()

สมัครเป็น:

res = cartesian_product({'col1': df1.col1, 'col3': df2.col3})
pd.merge(res, df1, on='col1')
#  col1 col3 col2
# 0   1    5    3
# 1   1    6    3
# 2   2    5    4
# 3   2    6    4

0

คุณสามารถใช้ numpy ได้เร็วขึ้น สมมติว่าคุณมีสองชุดดังต่อไปนี้

s1 = pd.Series(np.random.randn(100,))
s2 = pd.Series(np.random.randn(100,))

คุณแค่ต้องการ

pd.DataFrame(
    s1[:, None] @ s2[None, :], 
    index = s1.index, columns = s2.index
)

-1

ฉันพบว่าการใช้ Panda MultiIndex เป็นเครื่องมือที่ดีที่สุดสำหรับงานนี้ หากคุณมีรายชื่อlists_listให้เรียกpd.MultiIndex.from_product(lists_list)และทำซ้ำเหนือผลลัพธ์ (หรือใช้ในดัชนี DataFrame)

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