Pandas-不重叠的小组成员



我有以下数据帧:

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

数据按id和分数排序。

id表示DNA序列。

开始和结束表示id中的位置,我希望保留不重叠的切片,并且从重叠中只保留排名最高的:

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

有什么想法吗?

感谢

以下是

  • 添加一列来计算范围,并使用最大范围可以嵌套较小范围的任何内容这一事实
  • 在范围列上排序以利用此属性
  • 删除每个过程中嵌套的任何对象,这样它们就不会被多次比较

这只是为了让跑步变得简单。

import pandas as pd
import numpy as np
import StringIO as sio

data = """
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"""
data = pd.read_csv(sio.StringIO(data))

下一个区块完成工作。

data['range'] = data.end - data.start
data.sort_values(['id','range'])
g = data.groupby('id')
def f(df):
    keep = []
    while df.shape[0] > 0:
        widest = df.iloc[0]
        nested = (df.start >= widest.start) & (df.end <= widest.end)
        retain = df.loc[nested]
        loc = retain.score.values.argmax()
        keep.append(retain.iloc[[loc]])
        df = df.loc[np.logical_not(nested)]
    return pd.concat(keep,0)
out = g.apply(f).drop('range', 1)
out.index = np.arange(out.shape[0])

使用以上数据,输出

In[3]: out
Out[3]: 
   id  start  end  score
0  C1      2  592    157
1  C2    152  219    350
2  C2     13   70    319
3  C2     87  139    130
4  C2     92  140    102
5  C3     18   38    348
6  C3     31   57    310
7  C4    347   51    514

这更短,满足所有要求。您需要:

  1. 检查重叠的方法
  2. 一种按ID对数据进行分组的方法
  3. 一种在检查重叠后从每组中获取最佳结果的方法

这完成了所有这些,通过使用逻辑和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)

最新更新