2016-08-30 4 views
6

у меня есть панд dataframe, который выглядит так:Панды: Удаление строк на основе других строк

qseqid sseqid qstart qend 
2   1  125  345 
4   1  150  320 
3   2  150  450 
6   2  25  300 
8   2  50  500 

Я хотел бы удалить строки на основе других строк значений с этими критериями: ряд (r1) должно быть если другая строка (r2) существует с теми же sseqid и r1[qstart] > r2[qstart] и r1[qend] < r2[qend].

Возможно ли это с пандами?

ответ

7
df = pd.DataFrame({'qend': [345, 320, 450, 300, 500], 
'qseqid': [2, 4, 3, 6, 8], 
'qstart': [125, 150, 150, 25, 50], 
'sseqid': [1, 1, 2, 2, 2]}) 

def remove_rows(df): 
    merged = pd.merge(df.reset_index(), df, on='sseqid') 
    mask = ((merged['qstart_x'] > merged['qstart_y']) 
      & (merged['qend_x'] < merged['qend_y'])) 
    df_mask = ~df.index.isin(merged.loc[mask, 'index'].values) 
    result = df.loc[df_mask] 
    return result 

result = remove_rows(df) 
print(result) 

дает

qend qseqid qstart sseqid 
0 345  2  125  1 
3 300  6  25  2 
4 500  8  50  2 

Идея заключается в том, чтобы использовать pd.merge, чтобы сформировать DataFrame с каждой паре строк с тем же sseqid:

In [78]: pd.merge(df.reset_index(), df, on='sseqid') 
Out[78]: 
    index qend_x qseqid_x qstart_x sseqid qend_y qseqid_y qstart_y 
0  0  345   2  125  1  345   2  125 
1  0  345   2  125  1  320   4  150 
2  1  320   4  150  1  345   2  125 
3  1  320   4  150  1  320   4  150 
4  2  450   3  150  2  450   3  150 
5  2  450   3  150  2  300   6  25 
6  2  450   3  150  2  500   8  50 
7  3  300   6  25  2  450   3  150 
8  3  300   6  25  2  300   6  25 
9  3  300   6  25  2  500   8  50 
10  4  500   8  50  2  450   3  150 
11  4  500   8  50  2  300   6  25 
12  4  500   8  50  2  500   8  50 

Каждая строка объединены содержит данные из двух строк df. Вы можете сравнить каждые две строки, используя

mask = ((merged['qstart_x'] > merged['qstart_y']) 
     & (merged['qend_x'] < merged['qend_y'])) 

и найти метки в df.index, которые не соответствуют этому условию:

df_mask = ~df.index.isin(merged.loc[mask, 'index'].values) 

и выберите те строки:

result = df.loc[df_mask] 

Обратите внимание, что это Предполагается, что df имеет уникальный индекс.

+0

@unutbu - это отличная мысль о слиянии 'df.reset_index()' и 'df' :-) – Anzel

+0

Это потрясающе! Большое спасибо :) – jsgounot

Смежные вопросы