我有一个
df1
,每个项目都有一些item_id
和一些值(称为“节点”):
df1 = pd.DataFrame({'item_id':['1','1','1','2','2','2','3','3'],'nodes':['a','b','c','d','a','e','f','g']})
和一个
df2
,它是一个“向量”列表,其中每一行都是一个节点元组(可以在df1
中,但其中一些不是):
df2=pd.DataFrame({'vectors':[('a','b'),('b','c'),('d','f'),('e','b')]})
我需要计算
item_id
中不同 df1
的数量,它们在 df2
中至少有一个向量,因为可以从该项目的所有可能的节点组合构造一个向量。
例如
item_id = 1
有节点[a,b,c]
,所以可以组成这些向量:[(a,b),(a,c),(b,a),(b,c),(c,a),(c,b)]
。由于向量(a,b)
和(b,c)
存在于df2
中,那么我应该算item_id = 1
。但是,我不应该计算item_id = 2
,因为从其节点组合可以形成的所有向量中,它们都不在df2
中。
我不知道我怎样才能做到这一点。我可以获得节点所有可能组合的列表,以形成
item_id
中第一个 df1
的不同向量,使用:
from itertools import product
nodes_fa=df1[df1.item_id=="1"].nodes.to_list()
vectors_fa = pd.DataFrame(product(nodes_fa,nodes_fa),columns=['u','v'],dtype='str')
vectors_fa['vector'] = vectors_fa[["u", "v"]].agg(tuple, axis=1)
vectors_fa = vectors_fa[['vector']]
display(vectors_fa)
但我不知道如何将其扩展到所有
item_id
,也不知道如何检查此列表中的任何值是否在循环中的df2
中。
任何帮助将不胜感激。
itertools.combinations
和groupby.apply
,在set
/frozenset
的帮助下:
考虑无向边(
('a', 'b')
== ('b', 'a')
):
from itertools import combinations
S = set(frozenset(x) for x in df2['vectors'])
out = (
df1.groupby('item_id')['nodes']
.apply(lambda g: any(frozenset(t) in S for t in combinations(g, r=2)))
.sum()
)
对于有向边(
('a', 'b')
!= ('b', 'a')
):
from itertools import combinations
S = set(df2['vectors'])
out = (
df1.groupby('item_id')['nodes']
.apply(lambda g: any(t in S for t in combinations(g, r=2)))
.sum()
)
输出:
1
使用 pandas 函数的替代方案(可能效率较低):
s = (df1.groupby('item_id')['nodes']
.agg(lambda g: list(combinations(g, r=2)))
.explode()
)
out = s.isin(df2['vectors']).groupby(level=0).any().sum()