【问题标题】:Merge overlapping numeric ranges into continuous ranges将重叠的数值范围合并为连续范围
【发布时间】:2014-06-20 08:39:23
【问题描述】:

我正在尝试将一系列基因组坐标合并为连续范围,并提供一个用于跨间隙合并的附加选项。

例如,如果我有[[0, 1000], [5, 1100]] 的基因组范围,我希望结果是[0, 1100]。如果偏移选项设置为100,并且输入为[[0, 1000], [1090, 1000]],我将再次希望结果为[0, 1100]

我已经实现了一种执行此操作的方法,该方法依次遍历对齐并尝试在上一个结束位置和下一个起始位置上合并,但由于实际结果的长度不同,它失败了。例如,我的列表中有[[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

【问题讨论】:

    标签: python algorithm bioinformatics


    【解决方案1】:

    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))
    

    结果:

    [(138, 821), (900, 915)]
    [(138, 915)]
    

    它是如何工作的:我们标记每个起点和终点,然后我们排序,然后我们简单地为每个起点计数 up,为每个终点计数 down .如果我们访问了相同数量的起点和终点,则我们有一个封闭(连接)范围。

    【讨论】:

      【解决方案2】:

      那么,如何跟踪每个开始和结束以及每个位置所属的范围数?

      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。

      .....XXXXXo.............. (5-10)
      ........XXXXXXXo......... (8-15)
      ............Xo........... (12-13)
      ................XXXXo.... (16-20)
      .....1112221221111111.... number of ranges at each position
      .....----------------.... number of ranges > 0
      .....---------------..... overlap corrected (5-20)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-17
        • 2013-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多