大熊猫中的笛卡儿产品

时间:2012-11-07 12:33:13

标签: python 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]})

13 个答案:

答案 0 :(得分:64)

如果你有一个为每一行重复的键,那么你可以使用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']]

输出:

   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

答案 1 :(得分:23)

这不会赢得代码高尔夫比赛,并借鉴之前的答案 - 但清楚地显示了如何添加密钥以及联接的工作方式。这将从列表中创建2个新数据框,然后添加密钥以执行笛卡尔积。

我的用例是我需要列表中每周所有商店ID的列表。所以,我创建了一个我想要的所有周的列表,然后列出了我想要映射它们的所有商店ID。

我选择了左边的合并,但在此设置中在语义上与内部相同。你可以看到这个in the documentation on merging,它表明如果两个表中的键组合出现多次,它就会产生一个笛卡尔积 - 这就是我们设置的。

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)

答案 2 :(得分:21)

在其他空数据框中使用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

答案 3 :(得分:13)

作为替代方案,可以依赖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 :(得分:13)

此代码所需的最少代码。创建一个共同的密钥'笛卡儿将两者合并:

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

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

答案 5 :(得分:10)

使用方法链接:

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

答案 6 :(得分:4)

呈现给您

熊猫> = 1.2 [est]

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

import pandas as pd 

pd.__version__
# '1.1.0.dev0+3475.gd9845cf5d'

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​​的好处是,它可以节省大量的键入时间,并且可以很好地处理一些极端情况。除非您正在寻找something more performant,否则我几乎总是建议将此语法作为熊猫中笛卡尔乘积的首选。

答案 7 :(得分:2)

这是一个帮助函数,用于执行带有两个数据帧的简单笛卡尔积。内部逻辑使用内部键进行处理,并避免从任一侧弄乱任何碰巧被命名为“键”的列。

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

答案 8 :(得分:1)

mapzip理解

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

答案 9 :(得分:0)

如果没有重叠列,不想添加一列,并且可以丢弃数据帧的索引,这可能更容易:

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

答案 10 :(得分:0)

您可以先获取df1.col1df2.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

答案 11 :(得分: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
)

答案 12 :(得分:-1)

我发现使用pandas MultiIndex是这项工作的最佳工具。如果您有一个列表lists_list,请调用pd.MultiIndex.from_product(lists_list)并迭代结果(或在DataFrame索引中使用它)。