将重叠的数字范围合并为连续范围

2024-06-16 10:10:41 发布

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

我正在尝试将一系列的基因组坐标合并成连续的范围,还有一个额外的选择,可以跨间隙合并。在

例如,如果我有基因组范围[[0, 1000], [5, 1100]],我希望结果是[0, 1100]。如果{cd2>再次设置{cd3>,那么结果是。在

我已经实现了这样做的方法,逐步通过路线顺序,并试图合并上一个结束位置和下一个开始位置,但它失败了,因为实际结果有不同的长度。例如,我的列表中有按起始位置排序的结果[[138, 821],[177, 1158], [224, 905], [401, 1169]]。答案应该是[138, 1169],但我得到的却是[[138, 1158], [177, 905], [224, 1169]]。显然,我需要考虑的不仅仅是前一个结尾和下一个开始,但是我还没有找到一个好的解决方案(最好是不是一大堆if语句)。有人有什么建议吗?在

def overlap_alignments(align, gene, overlap):
    #make sure alignments are sorted first by chromosome then by start pos on chrom
    align = sorted(align, key = lambda x: (x[0], x[1]))
    merged = list()
    for i in xrange(1, len(align)):
        prv, nxt = align[i-1], align[i]
        if prv[0] == nxt[0] and prv[2] + overlap >= nxt[1]:
            start, end = prv[1], nxt[2]
            chrom = prv[0]
            merged.append([chrom, start, end, gene])
    return merged

Tags: 基因组byifmergedstartendnxtsorted
2条回答

Python来了batteries included

from itertools import chain

flatten = chain.from_iterable

LEFT, RIGHT = 1, -1

def join_ranges(data, offset=0):
    data = sorted(flatten(((start, LEFT), (stop + offset, RIGHT))
            for start, stop in data))
    c = 0
    for value, label in data:
        if c == 0:
            x = value
        c += label
        if c == 0:
            yield x, value - offset

if __name__ == '__main__':
    print list(join_ranges([[138, 821], [900, 910], [905, 915]]))
    print list(join_ranges([[138, 821], [900, 910], [905, 915]], 80))

结果:

^{pr2}$

工作原理:我们将每个起点和终点都标记为这样,然后进行排序,然后我们简单地对每个起点的向上计数,对每个终点计数向下。如果我们访问了相同数量的起点和终点,我们就有一个闭合(连接)范围。在

那么,记录每个位置的起点和终点以及每个位置所属范围的数量如何?在

def overlap_alignments(align, overlap):
    # create a list of starts and ends
    stends = [ (a[0], 1) for a in align ]
    stends += [ (a[1] + overlap, -1) for a in align ]
    stends.sort(key=lambda x: x[0])

    # now we should have a list of starts and ends ordered by position,
    # e.g. if the ranges are 5..10, 8..15, and 12..13, we have
    # (5,1), (8,1), (10,-1), (12,1), (13,-1), (15,-1)

    # next, we form a cumulative sum of this
    s = 0
    cs = []
    for se in stends:
        s += se[1]
        cs.append((se[0], s))
    # this is, with the numbers above, (5,1), (8,2), (10,1), (12,2), (13,1), (15,0)
    # so, 5..8 belongs to one range, 8..10 belongs to two overlapping range,
    # 10..12 belongs to one range, etc

    # now we'll find all contiguous ranges
    # when we traverse through the list of depths (number of overlapping ranges), a new
    # range starts when the earlier number of overlapping ranges has been 0
    # a range ends when the new number of overlapping ranges is zero 
    prevdepth = 0
    start = 0
    combined = []
    for pos, depth in cs:
        if prevdepth == 0:
            start = pos
        elif depth == 0
            combined.append((start, pos-overlap))
        prevdepth = depth

    return combined

这将更容易画出来,而不是解释。(是的,累积的总和可以用更短的空间来写,但我发现这样更清晰。)

为了以图形方式解释这一点,让我们输入([5,10],[8,15],[12,13],[16,20]),重叠=1。在

^{pr2}$

相关问题 更多 >