pandas 聚集连续检测的开始和结束以获知总持续时间

ehxuflar  于 2022-12-16  发布在  其他
关注(0)|答案(1)|浏览(107)

我一直在运行一个算法来检测一些音频文件中的声音。结果数据集包含检测开始和结束的时间。但是,预测每3秒进行一次,我希望聚合数据集以获得检测的长度。因此,如果第n+1行的start等于第n行的end,则应聚合这些行。
下面是我的数据集的外观:

data = {
    'filename': ['file1', 'file1', 'file1', 'file1', 'file1', 'file2', 'file2', 'file2', 'file2', 'file2'],
    'start': [21, 24, 27, 44, 60, 34, 37, 55, 58, 120],
    'end':  [24, 27, 30, 47, 63, 37, 40, 58, 61, 123]}
df = pd.DataFrame(data)

以下是我希望得到的:

r7s23pms

r7s23pms1#

下面是一个实现您所要求的方法:

import pandas as pd
data = {
    'filename': ['file0', 'file1', 'file1', 'file1', 'file1', 'file1', 'file2', 'file2', 'file2', 'file2', 'file2'],
    'start': [18,21, 24, 27, 44, 60, 34, 37, 55, 58, 120],
    'end':  [21, 24, 27, 30, 47, 63, 37, 40, 58, 61, 123]}
df = pd.DataFrame(data)
print(df)

df['continuation'] = (df.filename == df.filename.shift()) & (df.end.shift() == df.start)
df['keep'] = ~df.continuation.shift(-1).astype(bool)
df.at[df.index[-1], 'keep'] = True
df.start = df.start[~df.continuation]
df.start = df.start.fillna(method="ffill").astype(int)

df = ( df[df.keep]
    .assign(duration=df.end - df.start)
    .drop(columns=['continuation', 'keep']).reset_index(drop=True) )

print(df)

说明:

  • 在新continuation列中,用布尔值标记行,指示它们是否继续先前的声音检测
  • 在新的keep列中,将每个检测的最后一行(即,紧接在非连续行之前的每一行,以及 Dataframe 中的最后一行)标记为我们最终将保留的行
  • 确保我们打算保留的每行的start值用来自相同声音检测的第一行的start值更新;为此,请清空所有连续行中的start值,然后使用ffill向前填充这些空值
  • 仅筛选keep等于True的行,根据endstart计算duration,并删除中间列continuationkeep
  • 使用reset_index()重新编号行。

输出:

filename  start  end
0     file0     18   21
1     file1     21   24
2     file1     24   27
3     file1     27   30
4     file1     44   47
5     file1     60   63
6     file2     34   37
7     file2     37   40
8     file2     55   58
9     file2     58   61
10    file2    120  123
  filename  start  end  duration
0    file0     18   21         3
1    file1     21   30         9
2    file1     44   47         3
3    file1     60   63         3
4    file2     34   40         6
5    file2     55   61         6
6    file2    120  123         3

注意:我添加了一个文件名为file0的初始行,其end值与下一行(文件名为file1)的start值匹配,以证明不同文件之间没有聚合。
替代代码:

df['continuation'] = (df.filename == df.filename.shift()) & (df.end.shift() == df.start)
df['keep'] = ~df.continuation.shift(-1).astype(bool)
df.at[df.index[-1], 'keep'] = True
df['groupnum'] = df.keep.shift(fill_value=0).cumsum()
gb = df.groupby('groupnum')
df = pd.concat([gb.first()[['filename','start']], gb.last()['end']], axis=1).rename_axis(index=None)
df['duration'] = df.end - df.start
print(df)

说明:

  • 在如上所述创建continuationkeep列之后,使用cumsum为新列groupnum中的每一行分配声音检测索引
  • 使用groupbygroupnum对行进行分组
  • 使用concat分别从每个组的第一行和最后一行获取startend
  • 保持groupnum索引不变,使用rename_axis清空其名称,并计算新的duration列。

相关问题