Create distinct cluster for non-ordered sequences in Python
up vote
0
down vote
favorite
I have a dataframe containing "ID"s of persons in the first column. Each person can have up to 3 other persons that it is assigned into a unique group (or cluster) with. The related "CO_ID"s of a person are stored in 3 other columns. If a person is alone, i.e. there are no other persons assigned to it, it should be considered as it is in an one-person cluster anyway, the values of the other columns beeing nan. Same applies for persons who are only assigned to e.g. one other person: In this case one column contains a "CO_ID" while the other two columns beeing nan.
I wonder how I can assign those (through the CO_ID columns already excatly determined) clusters to each ID via an additional column called "CLUSTER"? Is there a prebuild function for this?
As it is obvious to see from the example data provided, the order of the "CO_ID"s is not important (for ID = ID1, it doesn't matter if CO_ID1 = ID2 and CO_ID2 = ID3 or CO_ID1 = ID3 and CO_ID2 = ID2).
The input data df1 looks like this:
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
And the desired output data df2 looks like this:
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
python python-3.x pandas combinations cluster-analysis
add a comment |
up vote
0
down vote
favorite
I have a dataframe containing "ID"s of persons in the first column. Each person can have up to 3 other persons that it is assigned into a unique group (or cluster) with. The related "CO_ID"s of a person are stored in 3 other columns. If a person is alone, i.e. there are no other persons assigned to it, it should be considered as it is in an one-person cluster anyway, the values of the other columns beeing nan. Same applies for persons who are only assigned to e.g. one other person: In this case one column contains a "CO_ID" while the other two columns beeing nan.
I wonder how I can assign those (through the CO_ID columns already excatly determined) clusters to each ID via an additional column called "CLUSTER"? Is there a prebuild function for this?
As it is obvious to see from the example data provided, the order of the "CO_ID"s is not important (for ID = ID1, it doesn't matter if CO_ID1 = ID2 and CO_ID2 = ID3 or CO_ID1 = ID3 and CO_ID2 = ID2).
The input data df1 looks like this:
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
And the desired output data df2 looks like this:
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
python python-3.x pandas combinations cluster-analysis
1
I believe there is a typo in your input and output. Should the 3rd row beID3 ID2 ID1 NaN
?ID3
is repeated twice
– ALollz
Nov 11 at 15:58
add a comment |
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I have a dataframe containing "ID"s of persons in the first column. Each person can have up to 3 other persons that it is assigned into a unique group (or cluster) with. The related "CO_ID"s of a person are stored in 3 other columns. If a person is alone, i.e. there are no other persons assigned to it, it should be considered as it is in an one-person cluster anyway, the values of the other columns beeing nan. Same applies for persons who are only assigned to e.g. one other person: In this case one column contains a "CO_ID" while the other two columns beeing nan.
I wonder how I can assign those (through the CO_ID columns already excatly determined) clusters to each ID via an additional column called "CLUSTER"? Is there a prebuild function for this?
As it is obvious to see from the example data provided, the order of the "CO_ID"s is not important (for ID = ID1, it doesn't matter if CO_ID1 = ID2 and CO_ID2 = ID3 or CO_ID1 = ID3 and CO_ID2 = ID2).
The input data df1 looks like this:
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
And the desired output data df2 looks like this:
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
python python-3.x pandas combinations cluster-analysis
I have a dataframe containing "ID"s of persons in the first column. Each person can have up to 3 other persons that it is assigned into a unique group (or cluster) with. The related "CO_ID"s of a person are stored in 3 other columns. If a person is alone, i.e. there are no other persons assigned to it, it should be considered as it is in an one-person cluster anyway, the values of the other columns beeing nan. Same applies for persons who are only assigned to e.g. one other person: In this case one column contains a "CO_ID" while the other two columns beeing nan.
I wonder how I can assign those (through the CO_ID columns already excatly determined) clusters to each ID via an additional column called "CLUSTER"? Is there a prebuild function for this?
As it is obvious to see from the example data provided, the order of the "CO_ID"s is not important (for ID = ID1, it doesn't matter if CO_ID1 = ID2 and CO_ID2 = ID3 or CO_ID1 = ID3 and CO_ID2 = ID2).
The input data df1 looks like this:
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
And the desired output data df2 looks like this:
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
python python-3.x pandas combinations cluster-analysis
python python-3.x pandas combinations cluster-analysis
edited Nov 13 at 17:41
asked Nov 11 at 13:06
Constantin
16611
16611
1
I believe there is a typo in your input and output. Should the 3rd row beID3 ID2 ID1 NaN
?ID3
is repeated twice
– ALollz
Nov 11 at 15:58
add a comment |
1
I believe there is a typo in your input and output. Should the 3rd row beID3 ID2 ID1 NaN
?ID3
is repeated twice
– ALollz
Nov 11 at 15:58
1
1
I believe there is a typo in your input and output. Should the 3rd row be
ID3 ID2 ID1 NaN
? ID3
is repeated twice– ALollz
Nov 11 at 15:58
I believe there is a typo in your input and output. Should the 3rd row be
ID3 ID2 ID1 NaN
? ID3
is repeated twice– ALollz
Nov 11 at 15:58
add a comment |
1 Answer
1
active
oldest
votes
up vote
2
down vote
accepted
Apply frozenset
row-wise to create distinct groups which are hashable and ordered (so which row they appear in is irrelevant). Group by these and use ngroup
to label each distinct group.
df1['Cluster'] = 'C'+ (df1.groupby(df1.apply(frozenset, 1), sort=False).ngroup()+1).astype('str')
Output
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
If performance is an issue, sort with numpy
. We'll need to replace the floating NaN
with strings so all values can be compared across columns.
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')
1
Check the running time stackoverflow.com/questions/51182228/…
– W-B
Nov 11 at 16:59
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
accepted
Apply frozenset
row-wise to create distinct groups which are hashable and ordered (so which row they appear in is irrelevant). Group by these and use ngroup
to label each distinct group.
df1['Cluster'] = 'C'+ (df1.groupby(df1.apply(frozenset, 1), sort=False).ngroup()+1).astype('str')
Output
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
If performance is an issue, sort with numpy
. We'll need to replace the floating NaN
with strings so all values can be compared across columns.
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')
1
Check the running time stackoverflow.com/questions/51182228/…
– W-B
Nov 11 at 16:59
add a comment |
up vote
2
down vote
accepted
Apply frozenset
row-wise to create distinct groups which are hashable and ordered (so which row they appear in is irrelevant). Group by these and use ngroup
to label each distinct group.
df1['Cluster'] = 'C'+ (df1.groupby(df1.apply(frozenset, 1), sort=False).ngroup()+1).astype('str')
Output
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
If performance is an issue, sort with numpy
. We'll need to replace the floating NaN
with strings so all values can be compared across columns.
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')
1
Check the running time stackoverflow.com/questions/51182228/…
– W-B
Nov 11 at 16:59
add a comment |
up vote
2
down vote
accepted
up vote
2
down vote
accepted
Apply frozenset
row-wise to create distinct groups which are hashable and ordered (so which row they appear in is irrelevant). Group by these and use ngroup
to label each distinct group.
df1['Cluster'] = 'C'+ (df1.groupby(df1.apply(frozenset, 1), sort=False).ngroup()+1).astype('str')
Output
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
If performance is an issue, sort with numpy
. We'll need to replace the floating NaN
with strings so all values can be compared across columns.
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')
Apply frozenset
row-wise to create distinct groups which are hashable and ordered (so which row they appear in is irrelevant). Group by these and use ngroup
to label each distinct group.
df1['Cluster'] = 'C'+ (df1.groupby(df1.apply(frozenset, 1), sort=False).ngroup()+1).astype('str')
Output
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
If performance is an issue, sort with numpy
. We'll need to replace the floating NaN
with strings so all values can be compared across columns.
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')
edited Nov 11 at 21:24
answered Nov 11 at 16:00
ALollz
10.5k31134
10.5k31134
1
Check the running time stackoverflow.com/questions/51182228/…
– W-B
Nov 11 at 16:59
add a comment |
1
Check the running time stackoverflow.com/questions/51182228/…
– W-B
Nov 11 at 16:59
1
1
Check the running time stackoverflow.com/questions/51182228/…
– W-B
Nov 11 at 16:59
Check the running time stackoverflow.com/questions/51182228/…
– W-B
Nov 11 at 16:59
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53249031%2fcreate-distinct-cluster-for-non-ordered-sequences-in-python%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
I believe there is a typo in your input and output. Should the 3rd row be
ID3 ID2 ID1 NaN
?ID3
is repeated twice– ALollz
Nov 11 at 15:58