Подтвердить что ты не робот

Декартовой продукции в pandas

У меня есть два фрейма pandas:

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]})
4b9b3361

Ответ 1

Если у вас есть ключ, который повторяется для каждой строки, вы можете создать декартово произведение, используя слияние (как в 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

Ответ 2

Это не выиграет соревнование по коду для гольфа и будет заимствовано из предыдущих ответов - но ясно показывает, как добавляется ключ и как работает объединение. Это создает 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)

Ответ 3

Используйте pd.MultiIndex.from_product как индекс в пустом информационном кадре, а затем reset его индекс, и все готово.

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

Ответ 4

В качестве альтернативы можно полагаться на декартово произведение, предоставляемое 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

Ответ 5

Минимальный код, необходимый для этого. Создайте общий "ключ" для декартовой слияния двух:

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

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

Ответ 6

С методом цепочки:

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

Ответ 7

map и zip в понимании

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

Ответ 8

Если у вас нет перекрывающихся столбцов, не хотите их добавлять, а индексы кадров данных могут быть отброшены, это может быть проще:

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

Ответ 9

Я считаю, что использование pandas MultiIndex - лучший инструмент для работы. Если у вас есть список списков lists_list, вызовите pd.MultiIndex.from_product(lists_list) и повторите результат (или используйте его в индексе DataFrame).