programing

판다의 데카르트 제품

testmans 2023. 6. 19. 21:18
반응형

판다의 데카르트 제품

두 개의 판다 데이터 프레임이 있습니다.

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

최근 버전의 Panda (>= 1.2)에서 이것은 다음과 같이 내장되어 있습니다.merge다음을 수행할 수 있습니다.

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

df1.merge(df2, how='cross')

이것은 이전의 팬더 < 1.2 정답과 동일하지만 읽기 더 쉽습니다.


판다 < 1.2:

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

사용하다pd.MultiIndex.from_product빈 데이터 프레임에서 인덱스로 사용한 다음 인덱스를 재설정하면 완료됩니다.

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

이 코드에는 최소한의 코드가 필요합니다.공통의 '키'를 만들어 두 개를 데카르트적으로 병합:

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

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

이것은 코드 골프 대회에서 우승하지 못할 것이며 이전 답변에서 차용한 것이지만 키가 추가되는 방법과 조인이 작동하는 방법을 명확하게 보여줍니다.그러면 목록에서 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)

메서드 체인 포함:

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

당신에게 발표하기

판다 >= 1.2

left.merge(right, how='cross')

import pandas as pd 

pd.__version__
# '1.2.0'

left = pd.DataFrame({'col1': [1, 2], 'col2': [3, 4]})
right = pd.DataFrame({'col3': [5, 6]}) 

left.merge(right, how='cross')

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

결과에서 인덱스가 무시됩니다.

구현 시에는 승인된 답변에 설명된 대로 공통 키 열에 조인하는 방법을 사용합니다.API를 사용하면 입력을 많이 절약할 수 있고 일부 코너 사례를 매우 잘 처리할 수 있습니다.저는 이 구문을 판다의 데카르트 제품에 대한 첫 번째 선호로 추천합니다. 만약 당신이 더 성능이 좋은 것을 찾고 있지 않다면 말이죠.

대안으로 iter 도구가 제공하는 데카르트 제품에 의존할 수 있습니다.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

겹치는 열이 없고 추가를 원하지 않으며 데이터 프레임의 인덱스가 삭제될 수 있는 경우 다음과 같은 방법이 더 쉬울 수 있습니다.

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

두 개의 데이터 프레임으로 간단한 데카르트 제품을 수행할 수 있는 도우미 기능이 있습니다.내부 논리는 내부 키를 사용하여 처리하며, 양쪽에서 "키"로 명명된 열을 망치는 것을 방지합니다.

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

당신은 데카르트 제품을 사용하는 것으로 시작할 수 있습니다.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

그러나 현재 버전의 Panda(1.1.5)에 대한 또 다른 해결 방법은 데이터 프레임이 아닌 시퀀스로 시작하는 경우에 특히 유용합니다.시간을 안 맞췄어요.인위적인 인덱스 조작은 필요하지 않지만 두 번째 시퀀스를 반복해야 합니다.은 그은특특의다니존합성에것라는 합니다.explode즉, 오른쪽 인덱스가 반복됩니다.

df1 = DataFrame({'col1': [1,2], 'col2': [3,4]})

series2 = Series(
    [[5, 6]]*len(df1),
    name='col3',
    index=df1.index,
)

df_cartesian = df1.join(series2.explode())

이 출력은

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

pyjanitor에서 expand_grid를 사용하여 교차 조인을 복제할 수 있습니다. 대규모 데이터셋에 대해 어느 정도 속도 성능을 제공합니다.np.meshgrid아래):

pip install git+https://github.com/pyjanitor-devs/pyjanitor.git
import pandas as pd
import janitor as jn
jn.expand_grid(others = {"df1":df1, "df2":df2})

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

저는 판다 멀티인덱스를 사용하는 것이 이 일에 가장 적합한 도구라고 생각합니다.lists_list, 전화 걸기pd.MultiIndex.from_product(lists_list)결과에 대해 반복합니다(또는 DataFrame 인덱스에 사용).

언급URL : https://stackoverflow.com/questions/13269890/cartesian-product-in-pandas

반응형