如何在Python中计算列值,当范围有重叠时进行累加

4

我有一个表格:

    id   start  end  stg
0   ZZ   0      25   5.0
1   ZZ   10     65   7.0
2   ZZ   30     50   2.0
3   ZZ   50     60   3.0
4   BB   0      2    5.6
5   BB   5      8    6.6
6   BB   8      13   18.0

我想要在区间[start,end]存在重叠的情况下将"stg"中的值相加,并创建新的区间和"stg"。输出应该像这样:
    id   start  end  stg
0   ZZ   0      10   5
1   ZZ   10     25   12
2   ZZ   25     30   7
3   ZZ   30     50   9
4   ZZ   50     60   10
5   ZZ   60     65   7
6   BB   0      5    5.6
7   BB   5      8    6.6
8   BB   8      13   18.0

我认为使用广播(一次性表格)操作来完成这个任务并不比迭代更有效率(尽管也许会有Pandas巫师出现并反驳我的说法)。因此,只需编写易于理解的显式循环即可,该循环适用于任何间隔序列或可迭代对象(或使用PyPI上的间隔库)。当然,如果你遇到困难,请回到这里提出具体问题,但这应该很容易。 - abarnert
问题在于我甚至不知道如何编写那个循环! - geek2000
你能发文本而不是图片吗?此外,我不确定预期的输出DataFrame是否完全准确。预期输出中缺少值60,而输入中没有75、80和110。 - Peter Leimbigler
1
@AntonvBR 我已将其发布为代码。 Peter,抱歉你是对的!我纠正了表格(由于手动计算仍可能存在错误),希望思路清晰。 - geek2000
1个回答

1
这只是一个部分解决方案,因为它完全忽略了 id。使用 IntervalIndex

示例数据

df = pd.DataFrame({'id': ['ZZ'] * 4, 
                   'start': [0, 10, 30, 50], 
                   'end': [25, 65, 50, 60], 
                   'stg': [5.0, 7.0, 2.0, 3.0]})
df = df[['id', 'start', 'end', 'stg']]

df
   id  start  end  stg
0  ZZ      0   25  5.0
1  ZZ     10   65  7.0
2  ZZ     30   50  2.0
3  ZZ     50   60  3.0

获取由起始值和结束值定义的最小子区间
subints = pd.IntervalIndex.from_breaks(sorted(np.unique(df[['start', 'end']].values.flatten())))
subints
IntervalIndex([(0, 10], (10, 25], (25, 30], (30, 50], (50, 60], (60, 65]]
              closed='right',
              dtype='interval[int64]')

在原始数据框上设置一个IntervalIndex。
idx = pd.IntervalIndex.from_arrays(df['start'], df['end'])
df.set_index(idx, inplace=True)
df
          id  start  end  stg
(0, 25]   ZZ      0   25  5.0
(10, 65]  ZZ     10   65  7.0
(30, 50]  ZZ     30   50  2.0
(50, 60]  ZZ     50   60  3.0

使用IntervalIndex切片在列表推导式中。
result = pd.DataFrame([(s.left, s.right, df2.loc[s]['stg'].sum()) 
                       for s in subints], 
                      columns=['start', 'end', 'stg'])
result
   start  end   stg
0      0   10   5.0
1     10   25  12.0
2     25   30   7.0
3     30   50   9.0
4     50   60  10.0
5     60   65   7.0

太好了!刚刚注意到一个错误:其中一个区间是(50, 50],我猜这不会有什么帮助哈哈。很快就会编辑更正。 - Peter Leimbigler
我可以接受那样;-)因为我正在绘制这些范围,单个点不会影响我的结果。但是提前感谢您修复代码。 - geek2000
@geek2000,听到这个消息很好。我想已经修复了:P(添加了np.unique - Peter Leimbigler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接