Python:如何查找三元组用户访问过的三元组

时间:2017-03-08 08:47:57

标签: python csv pandas

我有一个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或任何其他库。

2 个答案:

答案 0 :(得分:2)

您可以将transformsize一起使用,然后按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(下图中的中间一个)。

Bipartite graphs.

您可以使用此answermaximal 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) 

Bipartite graph B

让我们创建图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集也是如此。 Biparite graph connect_B

现在让我们搜索最大的集团:

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)

Complete bipartite graph K<sub>3,3</sub>