从依赖于其他行中多个值的行中删除行

2024-09-25 18:17:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我想删除前一个文件中已经包含的所有行开始:结束范围。你知道吗

示例df:

   length  qstart  qend  sstart  send
0    5464       1  5459       1  5460
1     400    3619  4015    4654  4258
2     396    4261  4653    4012  3619
3     203    1210  1411    1086  1287
4     203    5486  5689    5490  5693
5     100    5500  5600    5310  5410

通过看Q开始:qend,我想删除范围内包含的所有行/下/此行Q开始:qend(1:5459),并将此行为应用于所有剩余行。你知道吗

我尝试过制作掩码,并将数据帧合并到一起,类似于this post,但我无法拼凑出有用的东西。我还看了方向偏移()解决方案,但这只能查看行之间的固定间隔,而且据我所知不是动态的。我可以通过循环来解决这个问题,并像python一样对待它,但这是一个缓慢的方法,我想要一些更简单的方法

因此,如上所述,这是工作,但是缓慢的,不能很好地扩展。它也只适用于qstart:qend对,而不是另一个sstart:发送对(尽管在这个例子中输出是相同的)。你知道吗

df = pd.DataFrame({'length': {0: 5464, 1: 400, 2: 396, 3: 203, 4: 203, 5:100},
              'qstart': {0: 1, 1: 3619, 2: 4261, 3: 1210, 4: 5486, 5:5500},
              'qend': {0: 5459, 1: 4015, 2: 4653, 3: 1411, 4: 5689, 5:5600},
              'sstart': {0: 1, 1: 4654, 2: 4012, 3: 1086, 4: 5490, 5:5310},
              'send': {0: 5460, 1: 4258, 2: 3619, 3: 1287, 4: 5693, 5:5410}})


removeRows=[]
for i in range(len(df.index)-1):
    for j in range(i,len(df.index)):
        if df.iloc[j]['qstart']>df.iloc[i]['qstart']:
            if df.iloc[j]['qend']<df.iloc[i]['qend']:
                removeRows.append(j)
print(df[~df.index.isin(removeRows)])

   length  qstart  qend  sstart  send
0    5464       1  5459       1  5460
4     203    5486  5689    5490  5693

预期

输入(df按“长度”排序):

   length  qstart  qend  sstart  send
0    5464       1  5459       1  5460
1     400    3619  4015    4654  4258
2     396    4261  4653    4012  3619
3     203    1210  1411    1086  1287
4     203    5486  5689    5490  5693
5     100    5500  5600    5310  5410

输出:

   length  qstart  qend  sstart  send
0    5464       1  5459       1  5460
4     203    5486  5689    5490  5693

Tags: 方法insenddfforindexlenif
3条回答

解决方案1

这会产生预期的结果,但执行时间与两个for循环相当或较慢。你知道吗

df['remove'] = False            
for i in df.index:
    df['remove'].loc[(~df['remove']) & (df['qstart'] > df.loc[i, 'qstart']) & (df['qend'] < df.loc[i, 'qend'])] = True
ddf = df.loc[~df['remove']]

我首先添加一个名为'remove'的列,每个元素都设置为False,用于跟踪要删除的行。
索引上的循环根据您的条件更改为True列的元素'remove'。每一行都是这样。
然后您可以通过选择'remove'所在的所有行False来创建一个新的数据帧ddf。你知道吗

解决方案2

类似但更快的解决方案是循环行的组合:

from itertools import combinations
df['remove'] = False
for i, j in combinations(df.index, 2):
    if not df.loc[j, 'remove']:
        df.loc[j, 'remove'] = df.loc[j, 'qstart'] > df.loc[i, 'qstart'] and df.loc[j, 'qend'] < df.loc[i, 'qend']
ddf = df.loc[~df['remove']])

在概念上类似,但在这里我们选择每一对一次,这加快了执行时间。解决方案1 loc每次选择检查整个数据帧,因此有很多无用的比较。
根据我的测试,这应该比两个for循环快。你知道吗

对于这两种解决方案,使用

pd.options.mode.chained_assignment = None

提高执行时间。你知道吗

i = 0
while i < len(df):
    qstart = df['qstart'].iloc[i]
    qend = df['qend'].iloc[i]
    df = df.query('qstart <= @qstart or qend >= @qend')
    i += 1

其他可能的解决方案是使用

df.iterrows()

并实现if语句来检查所需的条件:

start = 0
end = 0
for x in df.iterrows(): 
    next_start = x[1]["qstart"]
    next_end = x[1]["qend"]
    if (start < next_start) & (end > next_end):
        df.drop(x[0], inplace = True)
    else:
        start = next_start.copy()
        end = next_end.copy()

然后可以使用

df.sort_values(by = "length")

相关问题 更多 >