Python 基于DataFrame列将数据分组到集群中

Python 基于DataFrame列将数据分组到集群中,python,pandas,dataframe,Python,Pandas,Dataframe,我有一个类似于以下内容的数据帧df: A B 1 2 1 3 1 4 2 5 4 6 4 7 8 9 9 8 我想添加一列,该列基本上根据a列和B列中的值确定相关集群: A B C 1 2 a 1 3 a 1 4 a 2 5 a 3 1 a 3 2 a 4 6 a 4 7 a 8 9 b 9 8 b

我有一个类似于以下内容的数据帧df:

A    B   
1    2
1    3
1    4
2    5
4    6
4    7
8    9
9    8
我想添加一列,该列基本上根据a列和B列中的值确定相关集群:

A    B    C   
1    2    a
1    3    a
1    4    a
2    5    a
3    1    a
3    2    a
4    6    a
4    7    a
8    9    b
9    8    b
请注意,由于A中的1与B中的2相关,而A中的2与B中的5相关,因此它们都位于同一集群中。A中的8只与B中的9相关,因此被放在另一个簇中


总而言之,我如何基于成对连接定义集群,其中成对由数据帧中的两列定义?

这里是一个开始,我不确定我是否理解分组为集群的标准,但是,您应该能够添加确切的标准:

import pandas as pd

x = pd.DataFrame({'A': [1,1,1,2,4,4,8,9],
              'B': [2,3,4,5,6,7,9,8]})

## calculate difference between a and be columns
## (substitute any distance/association function)
x['Diff'] = abs(x['A'] - x['B'])

## assign whether row is in a cluster or not.
x['Incluster'] = x['Diff'] <= 1

这是一个开始,我不确定我是否理解分组到集群的标准,但是,您应该能够添加确切的标准:

import pandas as pd

x = pd.DataFrame({'A': [1,1,1,2,4,4,8,9],
              'B': [2,3,4,5,6,7,9,8]})

## calculate difference between a and be columns
## (substitute any distance/association function)
x['Diff'] = abs(x['A'] - x['B'])

## assign whether row is in a cluster or not.
x['Incluster'] = x['Diff'] <= 1

您可以将其视为一个集合合并问题(每行描述一个集合),或一个连接组件问题(每行描述两个节点之间的边)。顺便说一句,虽然我已经考虑过提交一份PR,将其添加到实用工具中,但是它没有本机支持

无论如何,您可以做如下操作:

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
之后我们有

>>> df["C"] = df["A"].replace(group_ids(zip(df.A, df.B)))
>>> df
   A  B  C
0  1  2  0
1  1  3  0
2  1  4  0
3  2  5  0
4  4  6  0
5  4  7  0
6  8  9  1
7  9  8  1

您可以将0和1替换为您想要的任何内容。

您可以将其视为一个集合合并问题,每行描述一个集合,或一个连接组件问题,每行描述两个节点之间的边。顺便说一句,虽然我已经考虑过提交一份PR,将其添加到实用工具中,但是它没有本机支持

无论如何,您可以做如下操作:

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
之后我们有

>>> df["C"] = df["A"].replace(group_ids(zip(df.A, df.B)))
>>> df
   A  B  C
0  1  2  0
1  1  3  0
2  1  4  0
3  2  5  0
4  4  6  0
5  4  7  0
6  8  9  1
7  9  8  1

您可以用任何方式替换0和1。

群集由两个值之间是否存在成对连接来定义。在我的例子中,1,2+2,5表示1,5。此外,我的数据中可能有几百个簇,因此对簇罩的二进制确定是不够的。-好的,如果我理解正确,dataframe是一个表示图中连接的边列表。如果是这样,您可以在图中使用集群:或者集群由两个值之间是否存在成对连接来定义。在我的例子中,1,2+2,5表示1,5。此外,我的数据中可能有几百个簇,因此对簇罩的二进制确定是不够的。-好的,如果我理解正确,dataframe是一个表示图中连接的边列表。如果是这样,您可以在图中使用集群:或者