Pandas:如何通过联合间隔合并行

1tu0hz3e  于 2023-01-28  发布在  其他
关注(0)|答案(2)|浏览(149)

我对Pandas有点迷惑:我希望能够通过取事件相同的区间的并集来合并一个区间列,但只对分离的注解器这样做。例如,我的输入如下:

annotator  event          interval_presence
3          birds          [0,5]
3          birds          [7,9]
3          voices         [1,2]
3          traffic        [1,7]
5          voices         [4,7]
5          voices         [5,10]
5          traffic        [0,1]

其中“interval_presence”中的每一项都是一个列表。我希望将其作为输出:

annotator  event          interval_presence
3          birds          [[0,5],[7,9]]
3          voices         [1,2]
3          traffic        [1,7]
5          voices         [4,10]
5          traffic        [0,1]

我知道我可以使用python库“piso”来合并区间,但是我不知道如何合并不同事件和不同注解器上的区间,你知道如何像这样合并我的区间吗?

46scxncf

46scxncf1#

这似乎是pandas.DataFrame.groupbyitertools.groupy的 * 超级组合 * 的一个很好的例子:

from ast import literal_eval
from itertools import groupby​

# df["interval_presence"] = df["interval_presence"].apply(literal_eval) #uncomment this line if string literal
​​
def merge_overintervals(ser):
    ser.sort(key=lambda x: x[0])
    return [next(i) for _, i in groupby(ser, key=lambda x: x[1])]
​
out = df.groupby(["annotator", "event"], as_index=False, sort=False).agg(list)
​
out["interval_presence"] = out["interval_presence"].apply(merge_overintervals)

输出:

print(out)

   annotator    event interval_presence
0          3    birds  [[0, 5], [7, 9]]
1          3   voices          [[1, 2]]
2          3  traffic          [[1, 7]]
3          5   voices         [[4, 10]]
4          5  traffic          [[0, 1]]
  • NB:如果您需要在嵌套时获得扁平的1元素列表,请添加以下内容:*
from itertools import chain

out["interval_presence"]  = [x if len(x)>1 else list(chain(*x)) 
                             for x in out["interval_presence"]]
wxclj1h5

wxclj1h52#

使用以下示例数据:

data = pd.DataFrame({
    'annotator': [3, 3, 3, 3, 5, 5, 5],
    'event': ['birds', 'birds', 'voices', 'traffic', 'voices', 'voices', 'traffic'],
    'interval_presence': [[0,5], [7,9], [1,2], [1,7], [4,7], [5,10], [0,1]]
})

此代码将列表转换为间隔:

data['interval_presence'] = data['interval_presence'].apply(lambda x: pd.Interval(*x))

这个函数分组,然后对区间应用piso.union:

data = data.groupby(['annotator', 'event'])['interval_presence'] \
    .apply(pd.arrays.IntervalArray) \
    .apply(piso.union) \
    .reset_index()

不过,似乎piso目前只支持左闭或右闭的区间。这可能有更深层次的原因,但也可能只是过时了。例如,创建如下的区间:

data['interval_presence'] = data['interval_presence'].apply(lambda x: pd.Interval(*x), closed='both')

将获得AttributeError:“str”对象没有“closed”属性。

相关问题