大熊猫中的笛卡儿产品

Ido*_*dok 84 python pandas

我有两个pandas数据帧:

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

获得笛卡尔积的最佳做法是什么(当然不像我这样明确地写出来)?

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

Mat*_*ohn 72

如果你有一个为每一行重复的键,那么你可以使用merge生成一个笛卡尔积(就像在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']]
Run Code Online (Sandbox Code Playgroud)

输出:

   col1  col2  col3
0     1     3     5
1     1     3     6
2     2     4     5
3     2     4     6
Run Code Online (Sandbox Code Playgroud)

请参阅此处获取文档:http://pandas.pydata.org/pandas-docs/stable/merging.html#brief-primer-on-merge-methods-relational-algebra

  • 因此,要正确执行此操作,必须首先找到未使用的列名称,然后添加具有该名称的虚拟列,合并,最后将该列删除到结果中?与读取数据相比,使用 pandas 创建数据非常痛苦 (11认同)
  • @Bananach 哇!放松,我的朋友,事情并没有那么糟糕,他们只是还没有意识到这一点。请记住 pandas 仍然是一个正在开发的库,他们最近刚刚发布了 v1。无论如何,他们在 1.2 中的 df.merge() 中添加了对此的支持。有关更多信息,请参阅[此处](/sf/answers/4551228671/)。 (3认同)

Gij*_*ijs 41

使用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()
Run Code Online (Sandbox Code Playgroud)

出:

   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
Run Code Online (Sandbox Code Playgroud)

  • 您之所以投票不足,是因为您没有展示如何将多于1列的内容推广。 (5认同)
  • 我相信这是熊猫> = 0.21这些天最像熊猫的方式 (4认同)

Rob*_*ian 30

这不会赢得代码高尔夫比赛,并借鉴之前的答案 - 但清楚地显示了如何添加密钥,以及联接如何工作.这将从列表中创建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)
Run Code Online (Sandbox Code Playgroud)

  • 更短的版本:`days_and_stores = pd.merge(days.assign(key = 0),stores.assign(key = 0),on ='key').drop('key',axis = 1)` (17认同)

A.K*_*Kot 17

这个需要最少的代码.创建一个共同的'密钥'到笛卡尔合并两个:

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

df_cartesian = df1.merge(df2, how='outer')
Run Code Online (Sandbox Code Playgroud)

  • +`df_cartesian = df_cartesian.drop(columns = ['key'])`在最后清理 (3认同)

cs9*_*s95 15

呈现给你

熊猫 >= 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
Run Code Online (Sandbox Code Playgroud)

结果中将忽略索引。

在实现方面,这使用了已接受的答案中所述的公共键列方法的连接。使用 API 的好处是它可以为您节省大量的输入,并且可以很好地处理一些极端情况。我几乎总是推荐这种语法作为我对 Pandas 中笛卡尔积的首选,除非您正在寻找更高性能的东西


Sve*_*end 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)
Run Code Online (Sandbox Code Playgroud)

快速测试:

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
Run Code Online (Sandbox Code Playgroud)

  • 我测试了这个并且它可以工作,但它比大型数据集的合并答案慢得多. (2认同)

pom*_*ber 13

使用方法链接:

product = (
    df1.assign(key=1)
    .merge(df2.assign(key=1), on="key")
    .drop("key", axis=1)
)
Run Code Online (Sandbox Code Playgroud)