按重叠范围对行进行分组

Group rows by overlapping ranges

我有一个数据框,其中 left 列是对象最左边的位置,而 right 列是最右边的位置。如果对象重叠,或者它们重叠重叠的对象(递归),我需要对它们进行分组。 因此,例如,如果这是我的数据框:

     left  right
0      0    4
1      5    8
2      10   13
3      3    7
4      12   19      
5      18   23
6      31   35

所以行 03 重叠 - 因此它们应该在同一组中,而且行 1 与行 3 重叠 - 因此它加入了团体。

所以,对于这个例子,输出应该是这样的:

     left  right    group
0      0    4         0
1      5    8         0
2      10   13        1
3      3    7         0
4      12   19        1
5      18   23        1
6      31   35        2

想了各种方向,也没弄明白(没有丑for)。 任何帮助将不胜感激!

你能试试这个吗,使用 rolling maxrolling min,找到范围的交集:

df=df.sort_values(['left','right'])
df['Group']=((df.right.rolling(window=2,min_periods=1).min()-df.left.rolling(window=2,min_periods=1).max())<0).cumsum()


df.sort_index()
Out[331]: 
   left  right  Group
0     0      4      0
1     5      8      0
2    10     13      1
3     3      7      0
4    12     19      1
5    18     23      1
6    31     35      2

例如,(1,3) 和 (2,4) 找到交集

mix(3,4)-max(1,2)=1 ; 1大于0;那么两个区间有交集

我发现公认的解决方案(更新:现已删除)具有误导性,因为它无法推广到类似情况。例如对于以下示例:

df = pd.DataFrame({'left': [0,5,10,3,12,13,18,31], 
    'right':[4,8,13,7,19,16,23,35]})
df

建议的聚合函数输出以下数据帧(请注意,18-23 应与 12-19 一起在组 1 中)。

一种解决方案是使用以下方法(基于组合间隔的方法 posted by @CentAu):

# Union intervals by @CentAu
from sympy import Interval, Union
def union(data):
    """ Union of a list of intervals e.g. [(1,2),(3,4)] """
    intervals = [Interval(begin, end) for (begin, end) in data]
    u = Union(*intervals)
    return [u] if isinstance(u, Interval) \
        else list(u.args)

# Create a list of intervals
df['left_right'] = df[['left', 'right']].apply(list, axis=1)
intervals = union(df.left_right)

# Add a group column
df['group'] = df['left'].apply(lambda x: [g for g,l in enumerate(intervals) if 
l.contains(x)][0])

...输出:

您可以对样本进行排序并利用累积函数 cummaxcumsum。让我们举个例子:

   left  right
0     0      4
3     3      7
1     5      8
2    10     13
4    12     19
5    13     16
6    18     23
7    31     35

首先您需要对值进行排序,以便较长的范围排在第一位:

df = df.sort_values(['left', 'right'], ascending=[True, False])

结果:

   left  right
0     0      4
3     3      7
1     5      8
2    10     13
4    12     19
5    13     16
6    18     23
7    31     35

然后您可以通过将 'left' 与之前的 'right' 值进行比较来找到重叠组:

df['group'] = (df['right'].cummax().shift() <= df['left']).cumsum()
df.sort_index(inplace=True)

结果:

   left  right  group
0     0      4      0
1     5      8      0
2    10     13      1
3     3      7      0
4    12     19      1
5    13     16      1
6    18     23      1
7    31     35      2

一行: