Producto cartesiano en pandas.

Tengo dos marcos de datos de pandas:

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

¿Cuál es la mejor práctica para obtener su producto cartesiano (por supuesto, sin escribirlo explícitamente como yo)?

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

Si tiene una clave que se repite para cada fila, puede producir un producto cartesiano utilizando la combinación (como lo haría 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']] 

Salida:

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

Consulte aquí la documentación: http://pandas.pydata.org/pandas-docs/stable/merging.html#brief-primer-on-merge-methods-relational-algebra

Esto no ganará una competición de golf de código y se toma de las respuestas anteriores, pero muestra claramente cómo se agrega la clave y cómo funciona la unión. Esto crea 2 nuevos marcos de datos a partir de listas, luego agrega la clave para hacer el producto cartesiano.

Mi caso de uso fue que necesitaba una lista de todas las identificaciones de las tiendas para cada semana en mi lista. Entonces, creé una lista de todas las semanas que quería tener, luego una lista de todas las ID de las tiendas con las que quería mapearlas.

La combinación que elegí fue a la izquierda, pero sería semánticamente igual a la interna en esta configuración. Puede ver esto en la documentación sobre la fusión , que indica que hace un producto cartesiano si la combinación de teclas aparece más de una vez en ambas tablas, que es lo que configuramos.

 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) 

Use pd.MultiIndex.from_product como un índice en un dataframe de otro modo vacío, luego restablezca su índice, y listo.

 a = [1, 2, 3] b = ["a", "b", "c"] index = pd.MultiIndex.from_product([a, b], names = ["a", "b"]) pd.DataFrame(index = index).reset_index() 

afuera:

  ab 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 

Como alternativa, se puede confiar en el producto cartesiano proporcionado por itertools: itertools.product , que evita crear una clave temporal o modificar el índice:

 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) 

Examen rápido:

 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]: abcdef 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 

Código mínimo necesario para este. Cree una ‘clave’ común para fusionar los dos cartesianos:

 df1['key'] = 0 df2['key'] = 0 df_cartesian = df1.merge(df2, how='outer') 

Con el método de encadenamiento:

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

map y zip en una comprensión

 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 

Si no tiene columnas superpuestas, no desea agregar una, y los índices de los marcos de datos se pueden descartar, esto puede ser más fácil:

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

Me parece que el uso de pandas MultiIndex es la mejor herramienta para el trabajo. Si tiene una lista de listas lists_list , llame a pd.MultiIndex.from_product(lists_list) e itere sobre el resultado (o úsela en el índice DataFrame).