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]})
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
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)
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
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
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')
Avec chaînage de méthode:
product = (
df1.assign(key=1)
.merge(df2.assign(key=1), on="key")
.drop("key", axis=1)
)
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))
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
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).