如何检测公共元素列表并使用至少1个公共元素对列表进行分组?

时间:2019-06-20 10:55:27

标签: python pandas list networkx

我有一个带有1列(+索引)的数据框,其中包含子列表或元素的列表。 我想检测列表/子列表中的公共元素,并使用至少1个公共元素对列表进行分组,以便仅具有元素列表而不包含任何公共元素。 列表/子列表当前是这样的(例如4行):

                 Num_ID
Row1   [['A1','A2','A3'],['A1','B1','B2','C3','D1']]`

Row2   ['A1','E2','E3']

Row3   [['B4','B5','G4'],['B6','B4']]

Row4   ['B4','C9']

n个没有公共元素的列表(前两个示例):

['A1','A2','A3','B1','B2','C3','D1','E2','E3']
['B4','B5','B6','C9','G4']

1 个答案:

答案 0 :(得分:5)

您可以使用NetworkX的{​​{3}}方法。这是我适应这种connected_components解决方案的方式:

import networkx as nx
from itertools import combinations, chain

df= pd.DataFrame({'Num_ID':[[['A1','A2','A3'],['A1','B1','B2','C3','D1']], 
                            ['A1','E2','E3'], 
                            [['B4','B5','G4'],['B6','B4']], 
                            ['B4','C9']]})

首先将每个列表中的子列表展平:

L = [[*chain.from_iterable(i)] if isinstance(i[0], list) else i 
       for i in df.Num_ID.values.tolist()]

[['A1', 'A2', 'A3', 'A1', 'B1', 'B2', 'C3', 'D1'],
 ['A1', 'E2', 'E3'],
 ['B4', 'B5', 'G4', 'B6', 'B4'],
 ['B4', 'C9']]

鉴于列表/子列表包含2个以上的元素,您可以从每个子列表中获取所有长度为2的组合,并将它们用作网络边缘(请注意,边缘只能连接两个节点):

L2_nested = [list(combinations(l,2)) for l in L]
L2 = list(chain.from_iterable(L2_nested))

生成图形,并使用add_edges_from将列表添加为图形边缘。然后使用connected_components,它将为您精确地提供图中的一组已连接组件的列表:

G=nx.Graph()
G.add_edges_from(L2)
list(nx.connected_components(G))

[{'A1', 'A2', 'A3', 'B1', 'B2', 'C3', 'D1', 'E2', 'E3'},
 {'B4', 'B5', 'B6', 'C9', 'G4'}]