Python 连接两个数据帧,其中列值(一组)是另一个的子集

Python 连接两个数据帧,其中列值(一组)是另一个的子集,python,pandas,dataframe,Python,Pandas,Dataframe,我有两个数据帧: df1 = pd.DataFrame([[set(['foo', 'baz'])], [set(['bar', 'baz'])]], columns=['items']) items 0 {foo, baz} 1 {bar, baz} 目标是将df2与df1连接起来,其中df1.items中的值是df2.items的子集。两列都是一个集合 对于上下文,这是在实现apriori算法后将关联规则与客户购买关联起来 增加

我有两个数据帧:

df1 = pd.DataFrame([[set(['foo', 'baz'])],
                    [set(['bar', 'baz'])]], columns=['items'])



    items
0   {foo, baz}
1   {bar, baz}
目标是将df2与df1连接起来,其中df1.items中的值是df2.items的子集。两列都是一个集合

对于上下文,这是在实现apriori算法后将关联规则与客户购买关联起来

增加预期产出:

df3 = pd.DataFrame([[[set(['foo', 'baz'])], set(['bar', 'baz', 'foo']), 1],
                    [[set(['foo', 'baz'])], set(['bar', 'baz', 'foo']), 2],
                    [[set(['foo', 'baz'])], set(['bar', 'baz', 'foo']), 3],
                    [[set(['bar', 'baz'])], None, None]], columns=['items', 'items', 'other'])


    items           items           other
0   [{foo, baz}]    {foo, bar, baz} 1.0
1   [{foo, baz}]    {foo, bar, baz} 2.0
2   [{foo, baz}]    {foo, bar, baz} 3.0
3   [{bar, baz}]    None    NaN
创建数据帧

import pandas as pd

df1 = pd.DataFrame({'key': [1, 1],
                    'id': [0, 1],
                    'items': [set(['foo', 'baz']), set(['bar', 'baz'])]})

df2 = pd.DataFrame({'key': [1, 1, 1, 1],
                    'items': [set(['bar', 'baz', 'foo']), set(['bar', 'baz', 'foo']), set(['bar', 'baz', 'foo']), set(['one', 'two', 'bar'])],
                    'other': [1, 2, 3, 2]
                   })
然后做一个笛卡尔积

merged_df = df1.merge(df2, on='key')
merged_df

   key  id     items_x          items_y  other
0    1   0  {baz, foo}  {foo, baz, bar}      1
1    1   0  {baz, foo}  {foo, baz, bar}      2
2    1   0  {baz, foo}  {foo, baz, bar}      3
3    1   0  {baz, foo}  {one, bar, two}      2
4    1   1  {baz, bar}  {foo, baz, bar}      1
5    1   1  {baz, bar}  {foo, baz, bar}      2
6    1   1  {baz, bar}  {foo, baz, bar}      3
7    1   1  {baz, bar}  {one, bar, two}      2
定义自定义函数并查看它是否在一种情况下工作

def check_if_all_in_list(list1, list2):
    return all(elem in list2 for elem in list1)

check_if_all_in_list(merged_df['items_x'][0], merged_df['items_y'][0])
True
创造你的比赛

merged_df['check'] = merged_df.apply(lambda row: check_if_all_in_list(row['items_x'], row['items_y']), axis=1)
merged_df

   key  id     items_x          items_y  other  check
0    1   0  {baz, foo}  {foo, baz, bar}      1   True
1    1   0  {baz, foo}  {foo, baz, bar}      2   True
2    1   0  {baz, foo}  {foo, baz, bar}      3   True
3    1   0  {baz, foo}  {one, bar, two}      2  False
4    1   1  {baz, bar}  {foo, baz, bar}      1   True
5    1   1  {baz, bar}  {foo, baz, bar}      2   True
6    1   1  {baz, bar}  {foo, baz, bar}      3   True
7    1   1  {baz, bar}  {one, bar, two}      2  False
现在过滤掉你不想要的

mask = (merged_df['check']==True)
merged_df[mask]

   key  id     items_x          items_y  other  check
0    1   0  {baz, foo}  {foo, baz, bar}      1   True
1    1   0  {baz, foo}  {foo, baz, bar}      2   True
2    1   0  {baz, foo}  {foo, baz, bar}      3   True
4    1   1  {baz, bar}  {foo, baz, bar}      1   True
5    1   1  {baz, bar}  {foo, baz, bar}      2   True
6    1   1  {baz, bar}  {foo, baz, bar}      3   True

如果你想简单地根据条件过滤df2,那么选择。。。从X所在的表格中选择…-你可以做:

df2.loc[df2[items].applylambda x:anyel.intersectionx==df1[items]中el的el.tolist] 输出:

其他项目 0{foo,baz,bar}1 1{foo,baz,bar}2 2{foo,baz,bar}3 要实现类似左连接的效果,请执行以下操作:

将numpy作为np导入 df2[match]=df2[items]。applylambda x:anyel.intersectionx==df1[items]中el的el。tolist df2.loc[~df2[match],[other]]=np.nan df2.dropcolumns=match,inplace=True 输出:

其他项目 0{bar,baz,foo}1.0 1{bar,baz,foo}2.0 2{bar,baz,foo}3.0 三{二,巴,一}南
当X是Y和Z的子集时,您应该定义这种情况的逻辑。数据帧真的是理想的数据结构吗?总共有多少项,即所有集合的并集长度?@AlexanderCécile-我仍然计划对合并的数据帧执行许多操作/过滤器。不过我有兴趣听听其他的建议。最佳。@QuangHoang-范围为1-150。不过主要是在0-5范围内。这将起作用,而且实际上是通过熊猫的唯一选择,无论如何我可以看到这一点。显然,如果其中一个数据帧变大,则不会进行扩展。
mask = (merged_df['check']==True)
merged_df[mask]

   key  id     items_x          items_y  other  check
0    1   0  {baz, foo}  {foo, baz, bar}      1   True
1    1   0  {baz, foo}  {foo, baz, bar}      2   True
2    1   0  {baz, foo}  {foo, baz, bar}      3   True
4    1   1  {baz, bar}  {foo, baz, bar}      1   True
5    1   1  {baz, bar}  {foo, baz, bar}      2   True
6    1   1  {baz, bar}  {foo, baz, bar}      3   True