Q:

Pandas - non overlapping group members

I have the following dataframe:
id  start   end     score
C1  2       592     157
C1  179     592     87
C1  113     553     82
C2  152     219     350
C2  13      70      319
C2  13      70      188
C2  15      70      156
C2  87      139     130
C2  92      140     102
C3  18      38      348
C3  20      35      320
C3  31      57      310
C4  347     51      514

The data is ordered by the id and the score.
id represents a sequence of DNA.
Start and end represent positions in id and I would like to keep non overlapping slices and from the overlapping only the highest ranked:
id  start   end score
C1  2   592 157
C2  152 219 350
C2  13  70  319
C2  87  139 130
C3  18  38  348
C4  347 51  514

Any ideas?
Thanks

A:

This is shorter and meets all requirements. You need:

A way to check overlap
A way to group your data by ID
A way to grab the best from each group, after checking overlap.

This does all of those, cheating by using logic and groupby
# from Ned Batchfelder
# http://nedbatchelder.com/blog/201310/range_overlap_in_two_compares.html
def overlap(start1, end1, start2, end2):
    """
    Does the range (start1, end1) overlap with (start2, end2)?
    """
    return end1 >= start2 and end2 >= start1

def compare_rows(group):
    winners = []
    skip = []
    if len(group) == 1:
        return group[['start', 'end', 'score']]
    for i in group.index:
        if i in skip:
            continue
        for j in group.index:
            last = j == group.index[-1]
            istart = group.loc[i, 'start']
            iend = group.loc[i, 'end']
            jstart = group.loc[j, 'start']
            jend = group.loc[j, 'end']
            if overlap(istart, iend, jstart, jend):
                winner = group.loc[[i, j], 'score'].idxmax()
                if winner == j:
                    winners.append(winner)
                    skip.append(i)
                    break
            if last:
                winners.append(i)
    return group.loc[winners, ['start', 'end', 'score']].drop_duplicates()

grouped = df.groupby('id')
print grouped.apply(compare_rows)

