基于 DataFrame 列将数据分组到集群中
Group Data into Clusters Based on DataFrame Columns
我有一个与此类似的数据框 (df):
Node_Start
Node_End
1.0
208.0
1.0
911.0
800.0
1.0
3.0
800.0
2.0
511.0
700.0
3.0
200.0
4.0
我想根据 'Node_Start' 和 'Node_End' 列中的值添加一个显示相关聚类的列:
Node_Start
Node_End
Group
1.0
208.0
1
1.0
911.0
1
800.0
1.0
1
3.0
800.0
1
2.0
511.0
2
700.0
3.0
1
200.0
4.0
3
换句话说,由于 1.0 在 'Node_Start' 和 'Node_End' 中,因此它被分配到第 1 组。由于 800.0 连接到 1.0 和 3.0,这些行也被分配到第 1 组. 2.0 和 511.0 与任何其他行值无关,并分配给第 2 组。200.0 和 4.0 与任何其他行无关,并分配给第 3 组。依此类推...
以下代码实现了预期的结果,但有点笨拙,无法在我的整个数据集上运行,因为它太大(超过 500,000 行)并且我的内核在完成作业之前崩溃
def consolidate(sets):
# http://rosettacode.org/wiki/Set_consolidation#Python:_Iterative
setlist = [s for s in sets if s]
for i, s1 in enumerate(setlist):
if s1:
for s2 in setlist[i+1:]:
intersection = s1.intersection(s2)
if intersection:
s2.update(s1)
s1.clear()
s1 = s2
return [s for s in setlist if s]
def group_ids(pairs):
groups = consolidate(map(set, pairs))
d = {}
for i, group in enumerate(sorted(groups)):
for elem in group:
d[elem] = i
return d
这看起来是一个有向图。 Python 有一个很好的处理图形的模块:NetworkX
。你的问题似乎是关于寻找连接的组件。
所以我们可以首先构建一个图(对于问题的目的,定向性是无关紧要的,所以我们在这里删除该属性),其中节点是 df
中的元素,边是行。然后使用字典理解创建从节点到组件编号的映射,并将其 map
映射到其中一列:
import networkx as nx
arr = df.to_numpy()
G = nx.Graph()
G.add_edges_from(arr)
mapping = {node: i for i, component in enumerate(nx.connected_components(G), 1) for node in component}
df['Group'] = df['Node_Start'].map(mapping)
输出:
Node_Start Node_End Group
0 1.0 208.0 1
1 1.0 911.0 1
2 800.0 1.0 1
3 3.0 800.0 1
4 2.0 511.0 2
5 700.0 3.0 1
6 200.0 4.0 3
我有一个与此类似的数据框 (df):
Node_Start | Node_End |
---|---|
1.0 | 208.0 |
1.0 | 911.0 |
800.0 | 1.0 |
3.0 | 800.0 |
2.0 | 511.0 |
700.0 | 3.0 |
200.0 | 4.0 |
我想根据 'Node_Start' 和 'Node_End' 列中的值添加一个显示相关聚类的列:
Node_Start | Node_End | Group |
---|---|---|
1.0 | 208.0 | 1 |
1.0 | 911.0 | 1 |
800.0 | 1.0 | 1 |
3.0 | 800.0 | 1 |
2.0 | 511.0 | 2 |
700.0 | 3.0 | 1 |
200.0 | 4.0 | 3 |
换句话说,由于 1.0 在 'Node_Start' 和 'Node_End' 中,因此它被分配到第 1 组。由于 800.0 连接到 1.0 和 3.0,这些行也被分配到第 1 组. 2.0 和 511.0 与任何其他行值无关,并分配给第 2 组。200.0 和 4.0 与任何其他行无关,并分配给第 3 组。依此类推...
以下代码实现了预期的结果,但有点笨拙,无法在我的整个数据集上运行,因为它太大(超过 500,000 行)并且我的内核在完成作业之前崩溃
def consolidate(sets):
# http://rosettacode.org/wiki/Set_consolidation#Python:_Iterative
setlist = [s for s in sets if s]
for i, s1 in enumerate(setlist):
if s1:
for s2 in setlist[i+1:]:
intersection = s1.intersection(s2)
if intersection:
s2.update(s1)
s1.clear()
s1 = s2
return [s for s in setlist if s]
def group_ids(pairs):
groups = consolidate(map(set, pairs))
d = {}
for i, group in enumerate(sorted(groups)):
for elem in group:
d[elem] = i
return d
这看起来是一个有向图。 Python 有一个很好的处理图形的模块:NetworkX
。你的问题似乎是关于寻找连接的组件。
所以我们可以首先构建一个图(对于问题的目的,定向性是无关紧要的,所以我们在这里删除该属性),其中节点是 df
中的元素,边是行。然后使用字典理解创建从节点到组件编号的映射,并将其 map
映射到其中一列:
import networkx as nx
arr = df.to_numpy()
G = nx.Graph()
G.add_edges_from(arr)
mapping = {node: i for i, component in enumerate(nx.connected_components(G), 1) for node in component}
df['Group'] = df['Node_Start'].map(mapping)
输出:
Node_Start Node_End Group
0 1.0 208.0 1
1 1.0 911.0 1
2 800.0 1.0 1
3 3.0 800.0 1
4 2.0 511.0 2
5 700.0 3.0 1
6 200.0 4.0 3