为 Python 中的无序序列创建不同的集群
Create distinct cluster for non-ordered sequences in Python
我有一个数据框,其中第一列包含 "ID" 个人。每个人最多可以有 3 个其他人被分配到一个独特的组(或集群)中。一个人的相关 "CO_ID" 存储在其他 3 列中。如果一个人是单独的,即没有其他人分配给它,那么它应该被认为是一个人的集群,其他列的值是 nan。这同样适用于仅分配给例如另一个人:在这种情况下,一列包含 "CO_ID" 而其他两列是 nan.
我想知道如何通过名为 "CLUSTER" 的附加列将这些(通过已经明确确定的 CO_ID 列)分配给每个 ID?有没有预构建功能?
从提供的示例数据中可以明显看出,"CO_ID"s 的顺序并不重要(对于 ID = ID1,CO_ID1 = ID2 无关紧要和 CO_ID2 = ID3 或 CO_ID1 = ID3 和 CO_ID2 = ID2).
输入数据 df1 如下所示:
import pandas as pd
import numpy as np
df1 = pd.DataFrame({'ID' : ['ID1','ID2','ID3','ID4','ID5','ID6','ID7','ID8','ID9','ID10'] ,
'CO_ID1' : ['ID2','ID1','ID2','ID6','ID8','ID4','ID4','ID5', np.nan, 'ID4'],
'CO_ID2' : ['ID3','ID3','ID1', 'ID7', np.nan, 'ID7','ID6', np.nan, np.nan, 'ID6'],
'CO_ID3' : [np.nan, np.nan, np.nan, 'ID10', np.nan, 'ID10', 'ID10', np.nan, np.nan, 'ID7']})
Out[1]:
ID CO_ID1 CO_ID2 CO_ID3
0 ID1 ID2 ID3 NaN
1 ID2 ID1 ID3 NaN
2 ID3 ID2 ID1 NaN
3 ID4 ID6 ID7 ID10
4 ID5 ID8 NaN NaN
5 ID6 ID4 ID7 ID10
6 ID7 ID4 ID6 ID10
7 ID8 ID5 NaN NaN
8 ID9 NaN NaN NaN
9 ID10 ID4 ID6 ID7
所需的输出数据 df2 如下所示:
df2 = pd.DataFrame({'ID' : ['ID1','ID2','ID3','ID4','ID5','ID6','ID7','ID8','ID9','ID10'] ,
'CO_ID1' : ['ID2','ID1','ID2','ID6','ID8','ID4','ID4','ID5', np.nan, 'ID4'],
'CO_ID2' : ['ID3','ID3','ID1', 'ID7', np.nan, 'ID7','ID6', np.nan, np.nan, 'ID6'],
'CO_ID3' : [np.nan, np.nan, np.nan, 'ID10', np.nan, 'ID10', 'ID10', np.nan, np.nan, 'ID7'],
'Cluster' : ['C1','C1','C1','C2','C3','C2','C2','C3','C4','C2']})
Out[2]:
ID CO_ID1 CO_ID2 CO_ID3 Cluster
0 ID1 ID2 ID3 NaN C1
1 ID2 ID1 ID3 NaN C1
2 ID3 ID2 ID1 NaN C1
3 ID4 ID6 ID7 ID10 C2
4 ID5 ID8 NaN NaN C3
5 ID6 ID4 ID7 ID10 C2
6 ID7 ID4 ID6 ID10 C2
7 ID8 ID5 NaN NaN C3
8 ID9 NaN NaN NaN C4
9 ID10 ID4 ID6 ID7 C2
按行应用 frozenset
以创建可散列且有序的不同组(因此它们出现在哪一行是无关紧要的)。按这些分组并使用 ngroup
标记每个不同的组。
df1['Cluster'] = 'C'+ (df1.groupby(df1.apply(frozenset, 1), sort=False).ngroup()+1).astype('str')
输出
ID CO_ID1 CO_ID2 CO_ID3 Cluster
0 ID1 ID2 ID3 NaN C1
1 ID2 ID1 ID3 NaN C1
2 ID3 ID2 ID1 NaN C1
3 ID4 ID6 ID7 ID10 C2
4 ID5 ID8 NaN NaN C3
5 ID6 ID4 ID7 ID10 C2
6 ID7 ID4 ID6 ID10 C2
7 ID8 ID5 NaN NaN C3
8 ID9 NaN NaN NaN C4
9 ID10 ID4 ID6 ID7 C2
如果性能有问题,请按 numpy
排序。我们需要将浮动 NaN
替换为字符串,以便可以跨列比较所有值。
import numpy as np
d = pd.DataFrame(np.sort(df1.replace(np.NaN, 'NaN').values, 1), index=df1.index)
df1['Cluster'] = 'C'+(d.groupby(d.columns.tolist()).ngroup()+1).astype('str')
我有一个数据框,其中第一列包含 "ID" 个人。每个人最多可以有 3 个其他人被分配到一个独特的组(或集群)中。一个人的相关 "CO_ID" 存储在其他 3 列中。如果一个人是单独的,即没有其他人分配给它,那么它应该被认为是一个人的集群,其他列的值是 nan。这同样适用于仅分配给例如另一个人:在这种情况下,一列包含 "CO_ID" 而其他两列是 nan.
我想知道如何通过名为 "CLUSTER" 的附加列将这些(通过已经明确确定的 CO_ID 列)分配给每个 ID?有没有预构建功能?
从提供的示例数据中可以明显看出,"CO_ID"s 的顺序并不重要(对于 ID = ID1,CO_ID1 = ID2 无关紧要和 CO_ID2 = ID3 或 CO_ID1 = ID3 和 CO_ID2 = ID2).
输入数据 df1 如下所示:
import pandas as pd
import numpy as np
df1 = pd.DataFrame({'ID' : ['ID1','ID2','ID3','ID4','ID5','ID6','ID7','ID8','ID9','ID10'] ,
'CO_ID1' : ['ID2','ID1','ID2','ID6','ID8','ID4','ID4','ID5', np.nan, 'ID4'],
'CO_ID2' : ['ID3','ID3','ID1', 'ID7', np.nan, 'ID7','ID6', np.nan, np.nan, 'ID6'],
'CO_ID3' : [np.nan, np.nan, np.nan, 'ID10', np.nan, 'ID10', 'ID10', np.nan, np.nan, 'ID7']})
Out[1]:
ID CO_ID1 CO_ID2 CO_ID3
0 ID1 ID2 ID3 NaN
1 ID2 ID1 ID3 NaN
2 ID3 ID2 ID1 NaN
3 ID4 ID6 ID7 ID10
4 ID5 ID8 NaN NaN
5 ID6 ID4 ID7 ID10
6 ID7 ID4 ID6 ID10
7 ID8 ID5 NaN NaN
8 ID9 NaN NaN NaN
9 ID10 ID4 ID6 ID7
所需的输出数据 df2 如下所示:
df2 = pd.DataFrame({'ID' : ['ID1','ID2','ID3','ID4','ID5','ID6','ID7','ID8','ID9','ID10'] ,
'CO_ID1' : ['ID2','ID1','ID2','ID6','ID8','ID4','ID4','ID5', np.nan, 'ID4'],
'CO_ID2' : ['ID3','ID3','ID1', 'ID7', np.nan, 'ID7','ID6', np.nan, np.nan, 'ID6'],
'CO_ID3' : [np.nan, np.nan, np.nan, 'ID10', np.nan, 'ID10', 'ID10', np.nan, np.nan, 'ID7'],
'Cluster' : ['C1','C1','C1','C2','C3','C2','C2','C3','C4','C2']})
Out[2]:
ID CO_ID1 CO_ID2 CO_ID3 Cluster
0 ID1 ID2 ID3 NaN C1
1 ID2 ID1 ID3 NaN C1
2 ID3 ID2 ID1 NaN C1
3 ID4 ID6 ID7 ID10 C2
4 ID5 ID8 NaN NaN C3
5 ID6 ID4 ID7 ID10 C2
6 ID7 ID4 ID6 ID10 C2
7 ID8 ID5 NaN NaN C3
8 ID9 NaN NaN NaN C4
9 ID10 ID4 ID6 ID7 C2
按行应用 frozenset
以创建可散列且有序的不同组(因此它们出现在哪一行是无关紧要的)。按这些分组并使用 ngroup
标记每个不同的组。
df1['Cluster'] = 'C'+ (df1.groupby(df1.apply(frozenset, 1), sort=False).ngroup()+1).astype('str')
输出
ID CO_ID1 CO_ID2 CO_ID3 Cluster
0 ID1 ID2 ID3 NaN C1
1 ID2 ID1 ID3 NaN C1
2 ID3 ID2 ID1 NaN C1
3 ID4 ID6 ID7 ID10 C2
4 ID5 ID8 NaN NaN C3
5 ID6 ID4 ID7 ID10 C2
6 ID7 ID4 ID6 ID10 C2
7 ID8 ID5 NaN NaN C3
8 ID9 NaN NaN NaN C4
9 ID10 ID4 ID6 ID7 C2
如果性能有问题,请按 numpy
排序。我们需要将浮动 NaN
替换为字符串,以便可以跨列比较所有值。
import numpy as np
d = pd.DataFrame(np.sort(df1.replace(np.NaN, 'NaN').values, 1), index=df1.index)
df1['Cluster'] = 'C'+(d.groupby(d.columns.tolist()).ngroup()+1).astype('str')