您可以在graph theory 的帮助下解决您的问题。在您的情况下,您正在寻找类型为 K3,3 的complete bipartite graphs(下图中的中间那个)。
你可以使用这个answer在maximal cliques的帮助下找到所有最大完全二分图,然后过滤掉K3,3图。
示例:
我使用了networkx 包和jupyter notebook。
import networkx as nx
from networkx.algorithms import bipartite
from itertools import combinations, chain
让我们创建一个随机二分图(如您的 CSV 数据)。
B = bipartite.random_graph(n=8, m=8, p=0.5, seed=3)
print(B.edges)
打印:
[(0, 8), (0, 10), (0, 11), (0, 13), (0, 15), (1, 8), (1, 9), (1, 12), (1, 13), (1, 14), (2, 14), (2, 15), (3, 10), (3, 11), (3, 13), (3, 14), (4, 8), (4, 11), (4, 13), (4, 15), (5, 9), (5, 10), (5, 13), (5, 15), (6, 8), (6, 9), (6, 12), (6, 13), (6, 15), (7, 11), (7, 13)]
我用这个answer 创建了一个函数来绘制漂亮的二分图。
def draw_bipart(graph, set_X, set_Y):
pos = dict()
pos.update( (n, (1, i)) for i, n in enumerate(set_X) ) # put nodes from X at x=1
pos.update( (n, (2, i)) for i, n in enumerate(set_Y) ) # put nodes from Y at x=2
nx.draw(graph, pos=pos, with_labels=True)
X, Y = bipartite.sets(B) #two sets of data (in your case user_id and item_id)
%matplotlib inline
draw_bipart(B, X, Y)
让我们创建图 B 的副本并连接每个集合(X 和 Y)中的所有顶点,以便我们可以搜索派系。
connect_B = B.copy()
edges_X = combinations(X, 2)
edges_Y = combinations(Y, 2)
connect_B.add_edges_from(chain(edges_X, edges_Y))
draw_bipart(connect_B, X, Y)
现在集合 X (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) 中的每一对顶点都由一条边连接(由于重叠,并非全部可见)。 Y 集也是如此。
现在让我们搜索最大派系:
cliques = list(nx.find_cliques(connect_B))
print(cliques)
打印所有最大团:
[[2, 0, 4, 5, 6, 1, 3, 7], [2, 0, 4, 5, 6, 15], [2, 14, 1, 3], [2, 14, 15], [13, 0, 10, 11, 8, 15], [13, 0, 10, 11, 3], [13, 0, 10, 5, 3], [13, 0, 10, 5, 15], [13, 0, 4, 11, 8, 15], [13, 0, 4, 11, 3, 7], [13, 0, 4, 6, 1, 8], [13, 0, 4, 6, 1, 3, 5, 7], [13, 0, 4, 6, 15, 8], [13, 0, 4, 6, 15, 5], [13, 9, 8, 12, 6, 1], [13, 9, 8, 12, 6, 15], [13, 9, 8, 12, 14, 1], [13, 9, 8, 12, 14, 10, 11, 15], [13, 9, 5, 10, 15], [13, 9, 5, 6, 1], [13, 9, 5, 6, 15], [13, 14, 3, 1], [13, 14, 3, 10, 11]]
现在我们必须过滤 K3,3 图。我在这里使用两个条件:K3,3 图应该有 6 个顶点,其中 3 个应该属于一个集合。
cliques_K33 = [c for c in cliques if len(c) == 6 and len(X.intersection(c)) == 3]
print(cliques_K33)
打印:
[[13, 0, 4, 6, 15, 8]]
最后我们画出由找到的K3,3团的顶点诱导的图B的子图:
draw_bipart(B.subgraph(cliques_K33[0]), X, Y)