Я пошел дальше и создал решение, используя networkx
.Это выглядит следующим образом (расширенный пример)
import networkx as nx
import pandas as pd
df = pd.DataFrame({
'id': range(7),
'vmns': ('nan', 'a', 'a;b;c', 'c', 'b', 'd;e', 'e')
})
, что дает
id vmns
0 0 nan
1 1 a
2 2 a;b;c
3 3 c
4 4 b
5 5 d;e
6 6 e
Затем я создаю узлы из строк без точки с запятой и ребер из строк с точкой с запятой.Строки с nan
игнорируются.
# determine which rows contains nodes and which contains edges
edges_mask = df['vmns'].str.contains(';')
nodes_mask = ~df['vmns'].str.contains(';') & (df['vmns'] != 'nan')
def create_pairwise_edges(lst):
return [(lst[0], value) for value in lst[1:]]
# create the graph with nodes and edges
G = nx.Graph()
G.add_nodes_from(df.loc[nodes_mask, 'vmns'])
G.add_edges_from([st for row in df.loc[edges_mask, 'vmns'].str.split(';').map(create_pairwise_edges) for st in row])
# determine the connected components and write to df
Gcc = nx.connected_components(G)
new_map = dict()
for g, ids in enumerate(Gcc):
for id in ids:
new_map[id] = g
new_map['nan'] = 'nan'
df['combined_group'] = df['vmns'].str.split(';').map(lambda x: new_map[x[0]])
Результат -
id vmns combined_group
0 0 nan nan
1 1 a 0
2 2 a;b;c 0
3 3 c 0
4 4 b 0
5 5 d;e 1
6 6 e 1