Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 熊猫的笛卡尔积_Python_Pandas - Fatal编程技术网

Python 熊猫的笛卡尔积

Python 熊猫的笛卡尔积,python,pandas,Python,Pandas,我有两个数据帧: from pandas import DataFrame df1 = DataFrame({'col1':[1,2],'col2':[3,4]}) df2 = DataFrame({'col3':[5,6]}) 获得笛卡尔积的最佳实践是什么(当然,没有像我一样明确地写出来) 在Pandas(>=1.2)的最新版本中,这是内置在merge中的,因此您可以执行以下操作: from pandas import DataFrame df1 = DataFrame({'col

我有两个数据帧:

from pandas import DataFrame
df1 = DataFrame({'col1':[1,2],'col2':[3,4]})
df2 = DataFrame({'col3':[5,6]})     
获得笛卡尔积的最佳实践是什么(当然,没有像我一样明确地写出来)


在Pandas(>=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的熊猫:

如果每行都有一个重复的键,那么可以使用merge生成笛卡尔积(就像在SQL中一样)

输出:

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

有关文档,请参见此处:

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

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

这不会赢得代码高尔夫比赛,并借用了前面的答案-但清楚地显示了如何添加关键点,以及如何加入工作。这将从列表中创建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)

另一种选择是,您可以依赖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

我发现使用熊猫多重索引是这项工作的最佳工具。如果您有一个列表
lists\u list
,请调用
pd.MultiIndex.from\u product(lists\u list)
并迭代结果(或在数据帧索引中使用它)。

使用
pd.MultiIndex.from\u 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()
输出:


这个需要最少的代码。创建一个公共“键”,以笛卡尔方式合并这两个键:

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

df_cartesian = df1.merge(df2, how='outer')
使用方法链接:

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

您可以首先获取
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

下面是一个帮助函数,用于执行具有两个数据帧的简单笛卡尔乘积。内部逻辑使用内部键进行处理,并避免损坏任何一方碰巧命名为“键”的列

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
向您介绍

熊猫>=1.2 在结果中忽略索引



在实现方面,这使用了公认答案中描述的公共键列连接方法。使用API的好处在于,它可以节省大量的键入工作,并且可以很好地处理某些特殊情况。除非您正在寻找,否则我几乎总是建议将此语法作为我在pandas中使用笛卡尔积的第一个首选。

这看起来很有希望-但我在第一行遇到错误:
TypeError:“”不支持可变操作。
我可以通过添加
,index=[0,0]来解决此问题
到数据帧定义。或者使用
df1=df1.set_index([[0]*len(df1)])
(对于
df2
),同样如此。Racing Tadpole的编辑为我完成了这项工作-谢谢!略短一点的版本:
days\u和\u stores=pd.merge(days.assign(key=0),stores.assign(key=0),on='key').drop('key',axis=1)
您提到了交叉连接,但您使用的是熊猫数据帧,而不是spark数据帧.Dang。我没有思考。我经常一起使用spark+pandas,当我看到spark的更新时,我想到了这篇文章。谢谢Bryce。我测试了这个,它可以工作,但是对于大型数据集来说,它比上面的合并答案慢得多。@MrJ除了在这里使用ItErrors()之外,没有其他原因,它完全破坏了任何效率的表象,甚至几千行也需要几分钟或几小时。不值得。我相信这是熊猫>=0.21最近最像熊猫的方式。你有反对票,因为你还没有说明这将如何推广到任何超过1列的情况。此函数()使用参数的dict将其推广到任意数量的列表。这与这里的问题有点不同,它取两个数据帧的笛卡尔积(即,它不取
df1.col1
df.col2
)的积。事实上,我不认为
from_product
可以用于这个问题。@MaxGhenis认为这对这种情况没有用处,我们谈论的不是多个数组的笛卡尔乘积,而是两个或更多的数据帧(完全不同的故事)。+
df_cartesian=df_cartesian.drop(columns=['key'])
要在末尾进行清理,所以要正确地进行清理,必须首先找到一个未使用的列名,然后添加具有该名称的伪列,然后合并,最后删除结果栏?与阅读相反,用熊猫创建数据只是一个简单的过程pain@Bananach哇!放松点,我的朋友,事情没那么糟,他们只是还没开始。记住熊猫仍然是一个发展中的图书馆,他们最近才发布v1。无论如何,他们正在df.merge()中的1.2中添加对此的支持。更多信息请参见。@cs95谢谢,我没有注意到1.2版中会出现这种情况。在将来,这应该是首选方法如果您只想合并两列,您可以“匿名”创建df1和df2,如下所示:
df[[“purple”]]。merge(df[[“red”]],how=“cross”)
。请注意双括号
[[“colname”]]
,这使它们成为数据帧而不是系列。从pandas 1.2开始,您将很快能够使用
left.merge(right,how=“cross”)
,它将像魔术一样工作。看看这个。刚刚检查过,熊猫1.2于2020年12月26日发布。交叉合并对我有用!
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
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
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