판다의 데카르트 곱


108

두 개의 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]})

답변:


88

각 행에 대해 반복되는 키가있는 경우 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


6
이 작업을 제대로 수행하려면 먼저 사용하지 않는 열 이름을 찾은 다음 해당 이름을 가진 더미 열을 추가하고 병합 한 다음 마지막으로 결과에 열을 드롭해야합니까? 독서와 반대로, 만들기, 팬더와 데이터는 단지 고통
Bananach

68

사용 pd.MultiIndex.from_product그렇지 않으면 빈 dataframe의 지표로는 다음 인덱스를 재설정하면됩니다.

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

6
나는 이것이 요즘 판다에게 가장 판다 같은 방법이라고 믿는다> = 0.21
shadi

6
열이 두 개 이상인 항목에 대해 이것이 어떻게 일반화되는지 보여주지 않았기 때문에 비추천을 받았습니다.
cs95

이 함수 ( stackoverflow.com/a/58242079/1840471 )는 args의 dict를 사용하여 임의의 수의 목록으로 일반화합니다. 두 개의 DataFrame의 데카르트 곱을 취하는 여기의 질문과는 약간 다릅니다 (즉, df1.col1및 의 곱을 취하지 않음 df.col2).
Max Ghenis

사실 저는 from_product이 문제에 사용될 수 없다고 생각 합니다.
Max Ghenis

34

이것은 코드 골프 대회에서 이기지 않고 이전 답변에서 차용하지만 키가 추가되는 방법과 조인이 작동하는 방법을 명확하게 보여줍니다. 이렇게하면 목록에서 2 개의 새 데이터 프레임이 생성 된 다음 데카르트 곱을 수행 할 키가 추가됩니다.

내 사용 사례는 목록에서 매주 모든 상점 ID 목록이 필요하다는 것입니다. 그래서 저는 제가 갖고 싶었던 모든 주 목록을 만든 다음 매핑하려는 모든 상점 ID 목록을 만들었습니다.

내가 선택한 병합은 왼쪽이지만이 설정에서 의미 상 내부와 동일합니다. 병합에 대한 문서에서 이를 확인할 수 있습니다.이 문서 에서는 키 조합이 두 테이블 모두에 두 번 이상 나타나는 경우 카티 전 곱을 수행한다고 설명합니다.

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
좀 더 짧은 버전 :days_and_stores = pd.merge(days.assign(key=0), stores.assign(key=0), on='key').drop('key', axis=1)
Eugene Pakhomov

crossJoin을 언급했지만 스파크 데이터 프레임이 아닌 pandas 데이터 프레임을 사용하고 있습니다.
Bryce Guinta 2017

댕. 생각하지 않았다. 나는 스파크 + 팬더를 너무 자주 함께 사용하기 때문에 스파크 업데이트를 보았을 때이 게시물에 대해 생각했습니다. 감사합니다 브라이스.
Rob Guderian

32

이것에 필요한 최소한의 코드. 데카르트 병합에 공통 '키'를 생성하여 두 가지를 병합합니다.

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

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

8
+ df_cartesian = df_cartesian.drop(columns=['key'])끝에서 정리
StackG

22

메소드 체인 사용 :

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

14

대안으로 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

4
나는 이것을 테스트했고 작동하지만 큰 데이터 세트에 대한 위의 병합 답변보다 훨씬 느립니다.
MrJ

2

겹치는 열이없고 하나를 추가하고 싶지 않고 데이터 프레임의 인덱스를 삭제할 수있는 경우이 방법이 더 쉬울 수 있습니다.

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

1
이것은 유망 해 보이지만 첫 번째 줄에 오류가 TypeError: '<class 'pandas.core.index.Int64Index'>' does not support mutable operations. 있습니다 , index=[0,0]. 그래도 데이터 프레임 정의 에 추가하여이 문제를 해결할 수 있습니다 .
Racing Tadpole 2014 년

2
또는 사용 df1 = df1.set_index([[0]*len(df1)]))(및 유사하게 df2).
Racing Tadpole 2014 년

Racing Tadpole의 편집으로이 작업을 수행했습니다. 감사합니다!
Sevyns

2

다음은 두 개의 데이터 프레임으로 간단한 데카르트 곱을 수행하는 도우미 함수입니다. 내부 논리는 내부 키를 사용하여 처리하고 양쪽에서 "key"라는 이름이 붙은 열을 망가 뜨리는 것을 방지합니다.

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)

쇼 :

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

내가 7 살짜리 질문에 4 시간이 지난 대답이 있다는 것을 보았을 때 두 번 찍었습니다-이것에 대해 많은 감사를 표합니다 :)
Bruno E

0

df1.col1및 의 데카르트 곱을 취하여 시작한 df2.col3다음 다시 병합 df1하여 col2.

다음은 목록 사전을 취하는 일반적인 데카르트 곱 함수입니다.

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

적용 :

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

더 빠를 수 있으므로 numpy를 사용할 수 있습니다. 다음과 같이 두 개의 시리즈가 있다고 가정합니다.

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

당신은 단지 필요합니다.

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

-1

pandas MultiIndex를 사용하여 작업에 가장 적합한 도구를 찾습니다. 목록 목록이있는 경우 결과를 lists_list호출 pd.MultiIndex.from_product(lists_list)하고 반복합니다 (또는 DataFrame 인덱스에서 사용).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.