我有一个CSV文件,其中包含用户访问过的项目列表,例如:
user_id item_id
370 293
471 380
280 100
280 118
219 118
...
列表很长 - 30M行。
我需要找到三个用户访问过的项目的三元组(即所有三个用户都访问了这三个项目)。这种三胞胎很少见。我试图找到的示例结果:
user_id item_id
1 15
1 26
1 31
77 15
77 26
77 31
45 15
45 26
45 31
这样做的好方法是什么?我可以使用Pandas或任何其他库。
答案 0 :(得分:2)
您可以将transform
与size
一起使用,然后按boolean indexing
进行过滤:
print (df)
user_id item_id
0 1 15
1 1 26
2 1 31
3 77 15
4 77 26
5 77 31
6 45 15
7 45 26
8 45 31
9 370 293
10 471 380
11 280 100
12 280 118
13 219 118
print (df.groupby('user_id')['item_id'].transform('size'))
0 3
1 3
2 3
3 3
4 3
5 3
6 3
7 3
8 3
9 1
10 1
11 2
12 2
13 1
Name: item_id, dtype: int64
print (df[df.groupby('user_id')['item_id'].transform('size') == 3])
user_id item_id
0 1 15
1 1 26
2 1 31
3 77 15
4 77 26
5 77 31
6 45 15
7 45 26
8 45 31
使用filtration
的解决方案更慢:
df = df.groupby('user_id').filter(lambda x: len(x.item_id) == 3)
print (df)
user_id item_id
0 1 15
1 1 26
2 1 31
3 77 15
4 77 26
5 77 31
6 45 15
7 45 26
8 45 31
答案 1 :(得分:1)
您可以在graph theory的帮助下解决您的问题。对于您的情况,您正在寻找类型为K 3,3 的complete bipartite graphs(下图中的中间一个)。
您可以使用此answer在maximal cliques的帮助下找到所有最大的完整二部图,然后过滤掉K 3,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]]
现在我们必须过滤K 3,3 个图。我在这里使用两个条件:K 3,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]]
最后,我们从发现的K 3,3 派系中绘制由顶点诱发的图B的子图:
draw_bipart(B.subgraph(cliques_K33[0]), X, Y)