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