produit cartésien en pandas

J'ai deux pandas dataframes:

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

Quelle est la meilleure pratique pour obtenir leur produit cartésien (bien sûr, sans l'écrire explicitement comme moi)?

#df1, df2 cartesian product
df_cartesian = DataFrame({'col1':[1,2,1,2],'col2':[3,4,3,4],'col3':[5,5,6,6]})
54
demandé sur joaquin 2012-11-07 16:33:12

9 réponses

Si vous avez une clé qui est répétée pour chaque ligne, vous pouvez produire un produit cartésien en utilisant merge (comme vous le feriez en 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']]

Voir ici pour la documentation: http://pandas.pydata.org/pandas-docs/stable/merging.html#brief-primer-on-merge-methods-relational-algebra

51
répondu Matti John 2012-11-07 12:47:36

Cela ne gagnera pas une compétition de golf de code , et emprunte aux réponses précédentes - mais montre clairement comment la clé est ajoutée et comment la jointure fonctionne. Cela crée 2 nouvelles trames de données à partir de listes, puis ajoute la clé pour faire le produit cartésien.

Mon cas d'utilisation était que j'avais besoin d'une liste de tous les magasin d'Identifiants pour chaque semaine dans ma liste. Donc, j'ai créé une liste de toutes les semaines, je voulais l'avoir, alors une liste de tous les magasins Id je voulais la carte contre.

La fusion que j'ai choisie est partie, mais serait sémantiquement le même que intérieure dans cette configuration. Vous pouvez voir ceci dans la documentation sur la fusion , qui indique qu'il fait un produit cartésien si la combinaison de touches apparaît plus d'une fois dans les deux tables - ce que nous avons mis en place.

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)
20
répondu Rob Guderian 2017-04-18 14:08:48

Comme alternative, on peut s'appuyer sur le produit cartésien fourni par itertools: itertools.product, ce qui évite de créer une clé temporaire ou de modifier l'index:

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)

Test Rapide:

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
9
répondu Svend 2016-11-03 14:42:24

Utilisez pd.MultiIndex.from_product comme index dans un dataframe autrement vide, puis réinitialisez son index, et vous avez terminé.

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

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

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

Out:

   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
répondu Gijs 2017-10-14 11:32:20

Code Minimal nécessaire pour celui-ci. Créez une 'clé' commune pour fusionner les deux cartésiens:

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

df_cartesian = df1.merge(df2, how='outer')
5
répondu A.Kot 2017-10-23 18:15:43

Avec chaînage de méthode:

product = (
    df1.assign(key=1)
    .merge(df2.assign(key=1), on="key")
    .drop("key", axis=1)
)
2
répondu pomber 2018-03-16 16:53:32

Si vous n'avez pas de colonnes qui se chevauchent, ne voulez pas en ajouter une et que les indices des trames de données peuvent être ignorés, cela peut être plus facile:

df1.index[:] = df2.index[:] = 0
df_cartesian = df1.join(df2, how='outer')
df_cartesian.index[:] = range(len(df_cartesian))
0
répondu sergeyk 2013-03-25 02:58:01

map et zip dans une compréhension de la

DataFrame([
    d1 + d2
    for d1 in zip(*map(df1.get, df1))
    for d2 in zip(*map(df2.get, df2))
], columns=df1.columns.append(df2.columns))

   col1  col2  col3
0     1     3     5
1     1     3     6
2     2     4     5
3     2     4     6
0
répondu piRSquared 2018-09-11 14:19:44

Je trouve que l'utilisation de pandas MultiIndex est le meilleur outil pour le travail. Si vous avez une liste de listes lists_list, appelez pd.MultiIndex.from_product(lists_list) et parcourez le résultat (ou utilisez-le dans l'index DataFrame).

-1
répondu Ankur Kanoria 2017-09-05 06:43:58