pandalarda kartezyen ürün


109

İki panda veri çerçevem ​​var:

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

Kartezyen ürünlerini elde etmenin en iyi yolu nedir (tabii ki benim gibi açıkça yazmadan)?

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

Yanıtlar:


88

Her satır için tekrarlanan bir anahtarınız varsa, birleştirme kullanarak kartezyen bir ürün üretebilirsiniz (SQL'de olduğu gibi).

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

Çıktı:

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

Belgeler için buraya bakın: http://pandas.pydata.org/pandas-docs/stable/merging.html#brief-primer-on-merge-methods-relational-algebra


6
Öyleyse, bunu düzgün bir şekilde yapmak için önce kullanılmayan bir sütun adı bulmalı, sonra bu ada sahip sahte sütunlar eklemeli, birleştirmeli ve son olarak sütunu sonuca bırakmalı mı? Okumanın aksine, pandalarla veri oluşturmak sadece bir acıdır
Bananach

69

pd.MultiIndex.from_productBoş bir veri çerçevesinde bir dizin olarak kullanın , ardından dizinini sıfırlayın ve bitirdiniz.

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

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

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

dışarı:

   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
Bunun pandalar için bugünlerde en pandaya benzer yol olduğuna inanıyorum> = 0.21
shadi

6
Olumsuz oylar aldınız çünkü bunun 1'den fazla sütunu olan herhangi bir şeyi nasıl genelleyeceğini göstermediniz.
cs95

Bu işlev ( stackoverflow.com/a/58242079/1840471 ), onu bir bağımsız değişkenler diktesi kullanarak rastgele sayıda listeye genelleştirir. (Bunu ürününü almıyor yani iki DataFrames Kartezyen çarpımı burada sorusuna biraz farklı olduğunu df1.col1ve df.col2).
Max Ghenis

Aslında from_productbu problem için kullanılabileceğini sanmıyorum .
Max Ghenis

34

Bu bir kod golf yarışmasını kazanmayacak ve önceki cevaplardan ödünç alıyor - ancak anahtarın nasıl eklendiğini ve birleştirme işleminin nasıl çalıştığını açıkça gösteriyor. Bu, listelerden 2 yeni veri çerçevesi oluşturur, ardından kartezyen ürünü yapmak için anahtarı ekler.

Kullanım durumum, listemdeki her hafta için tüm mağaza kimliklerinin bir listesine ihtiyacım olmasıydı. Bu yüzden, sahip olmak istediğim tüm haftaların bir listesini ve ardından bunları eşleştirmek istediğim tüm mağaza kimliklerinin bir listesini oluşturdum.

Solu seçtiğim birleştirme, ancak anlamsal olarak bu kurulumdaki iç ile aynı olacaktır. Bunu, her iki tabloda da tuş kombinasyonu birden fazla göründüğünde Kartezyen ürünü olduğunu belirten birleştirme ile ilgili belgelerde görebilirsiniz - biz de bunu kurarız.

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
Biraz daha kısa versiyon:days_and_stores = pd.merge(days.assign(key=0), stores.assign(key=0), on='key').drop('key', axis=1)
Eugene Pakhomov

CrossJoin'den bahsediyorsunuz, ancak kıvılcım veri çerçevesi değil, pandalar veri çerçevesi kullanıyorsunuz.
Bryce Guinta

Dang. Düşünmüyordum. Kıvılcım + pandaları o kadar sık ​​kullanıyorum ki kıvılcım için güncellemeyi görünce bu yazıyı düşündüm. Teşekkürler Bryce.
Rob Guderian

32

Bunun için minimum kod gerekli. Kartezyen ikisini birleştirmek için ortak bir 'anahtar' oluşturun:

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

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

8
+ df_cartesian = df_cartesian.drop(columns=['key'])sonunda temizlemek için
StackG

22

Yöntem zincirleme ile:

product = (
    df1.assign(key=1)
    .merge(df2.assign(key=1), on="key")
    .drop("key", axis=1)
)

14

Alternatif olarak, itertools tarafından sağlanan kartezyen ürüne güvenilebilir: bu itertools.product, geçici bir anahtar oluşturmayı veya dizini değiştirmeyi önler:

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)

Hızlı test:

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
Bunu test ettim ve işe yarıyor, ancak büyük veri kümeleri için yukarıdaki birleştirme yanıtlarından çok daha yavaş.
MrJ

2

Çakışan sütunlarınız yoksa, bir tane eklemek istemiyorsanız ve veri çerçevelerinin indisleri atılabiliyorsa, bu daha kolay olabilir:

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

1
Bu umut verici görünüyor - ancak ilk satırda hatayı alıyorum: Yine de dataframe tanımına TypeError: '<class 'pandas.core.index.Int64Index'>' does not support mutable operations. ekleyerek , index=[0,0]bunu aşabilirim.
Racing Kurbağa

2
Veya kullanarak df1 = df1.set_index([[0]*len(df1)]))(ve benzer şekilde df2).
Racing Kurbağa Yavrusu

Yarış Kurbağa'nın düzenlemeleri bu işi benim için yaptı - teşekkürler!
Sevyns

2

İki veri çerçevesi ile basit bir Kartezyen ürünü gerçekleştirmek için yardımcı bir işlev aşağıda verilmiştir. Dahili mantık, dahili bir anahtar kullanarak idare eder ve her iki taraftan "anahtar" olarak adlandırılan sütunların karıştırılmasını önler.

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)

gösterir:

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

7 yaşındaki bir sorunun 4 saatlik bir cevabı olduğunu görünce iki kez aldım - bunun için çok teşekkürler :)
Bruno E

0

Kartezyen ürününü alarak başlayabilir df1.col1ve df2.col3daha sonra df1elde etmek için tekrar birleşebilirsiniz col2.

Listelerden oluşan bir sözlüğü alan genel bir Kartezyen ürün işlevi:

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

Farklı uygula:

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

Daha hızlı olabileceği için numpy kullanabilirsiniz. Aşağıdaki gibi iki seriniz olduğunu varsayalım,

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

Sadece ihtiyacın var,

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

-1

Pandalar MultiIndex'i bu iş için en iyi araç olarak görüyorum. Bir liste listeniz varsa , sonucu lists_listarayın pd.MultiIndex.from_product(lists_list)ve yineleyin (veya DataFrame dizininde kullanın).

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.