【问题标题】:Pandas - non overlapping group membersPandas - 非重叠组成员
【发布时间】:2016-02-12 22:56:10
【问题描述】:

我有以下数据框:

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和score排序。

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

有什么想法吗?

谢谢

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    这更短并且满足所有要求。你需要:

    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)
    

    【讨论】:

    • 谢谢!我只是稍微修改了 istart、iend、jstart 和 jend 的值分配,因为有时感兴趣的片段可以反转。 istart, iend = sorted([group.loc[i,'start'],group.loc[i,'end']])jstart, jend = sorted([group.loc[j,'start'],group.loc[j,'end']])
    【解决方案2】:

    这是一个较短的版本

    • 添加一列来计算范围,并利用最大范围可以嵌套任何具有较小范围的事实
    • 对范围列进行排序以利用此属性
    • 删除每个通道中嵌套的任何内容,以便它们不会被多次比较。

    这只是为了方便运行而设置的。

    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
    

    【讨论】:

    • 假设数据不是嵌套的,只是部分重叠?我认为nested = (df.start &gt;= widest.start) &amp; (df.end &lt;= widest.end) 太严格了。不过,比我的效率高得多!
    • 我考虑过那个案例,但认为这个问题没有足够的细节来确定如何解决非重叠案例的规则集。例如,假设您有 [1,5] 与 val=1、[1,3] 与 val=3 和 [2,4] 与 val=3。在这种情况下,显然 [1,3] 或 [2,4] 都比 [1,5] 好,但由于这两个不重叠,我确定应该返回什么。
    • 我同意打破平局的问题,只是想我会提出这个问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-21
    • 1970-01-01
    相关资源
    最近更新 更多