【问题标题】:Filter a list of integer ranges by both a maximum overlap percentage and value按最大重叠百分比和值过滤整数范围列表
【发布时间】:2019-09-20 18:10:31
【问题描述】:

我有一个范围列表,例如:

[12-48,40-80,60-105,110-130,75-400]

而且我需要过滤掉或删除重叠超过 x 位(例如重叠超过 10 个)和/或重叠超过 x%(比如说 20%)的最小比较范围的范围。

目前,我使用 for 循环一次检查每个范围并将其与下一个范围进行比较,以查看它们是否重叠超过了我规定的限制,如果是,请将其删除。这与我展示的示例中的结果不同:

[12-48,75-400]

范围 [40-80] 不应该被删除,因为它不与我们剩余的 2 个超出限制的范围重叠,但因为它与 [60-105] 重叠并且是 2 个中较小的一个,所以它被删除了。正确的剩余范围应该是:

[12-48,40-80,75-400]

我不认为一个简单的 for 循环是这里的解决方案,但我不知所措。如果有什么不清楚的地方请告诉我。

当前代码

GeneA/GenePrev/GeneAND 部分是我计算重叠百分比的方法,可以忽略。

        start = int(key.split(',')[0])
        stop = int(key.split(',')[1])
        length = stop - start
        if First == True:
            Both_Frames[key] = value
            First = False
            GeneA[start:stop] = [1] * (stop - start)
            GenePrev = GeneA
            PrevStart = start
            PrevStop = stop
            prevlength = PrevStop - PrevStart
        else:
            GeneA[start:stop] = [1] * (stop - start)
            Gene_AND = GenePrev & GeneA

            if start == PrevStart:
                GenePrev = GeneA
                
                ######Need to delete item from dictionary which is overlapping
                Both_Frames.popitem(last=False)
                Both_Frames[key] = value
                PrevStart = start
                PrevStop = stop
                prevlength = PrevStop - PrevStart
            elif start >= PrevStart and stop <= PrevStop:
           
                continue
            elif  np.count_nonzero(Gene_AND) <= (length * OverLapPercentage) and np.count_nonzero(Gene_AND) <= OverLapNT:
                GenePrev = GeneA
                Both_Frames[key] = value
                PrevStart = start
                PrevStop = stop
                prevlength = PrevStop - PrevStart

            elif np.count_nonzero(Gene_AND) >= (length * OverLapPercentage) or np.count_nonzero(Gene_AND) >= OverLapNT:
                if length > prevlength:
                    GenePrev = GeneA
                 
                    Both_Frames.popitem(last=False)
                    Both_Frames[key] = value
                    PrevStart = start
                    PrevStop = stop
                    prevlength = PrevStop - PrevStart

【问题讨论】:

  • 您能否编辑并添加您所描述的实际代码?现在您只是要求我们为您解决这个问题。
  • 这是一个怪物 - 添加到底部
  • 我不确定我是否理解。为什么我们不能将[12-48,40-80,110-130] 作为最终结果?这些范围之间的重叠也不超过10?
  • 110-130 正好落在 75-400 之间。我应该说如果范围在另一个范围内,那么它也会被删除。
  • 什么是“重叠百分比”?这是否意味着两个感兴趣的元组中最大和最小数字之间范围的 20%? // 我们可以假设“数据”(元组列表)是“排序的”,也就是说,我们只是在两个相邻索引之间进行比较? // 总的来说,你能更好地定义你想要完成的事情吗?

标签: python list range overlap


【解决方案1】:

我可能会给你一个复杂的解决方案:

首先,我将您的范围转换为listtuplesint

import pandas as pd


r = ["12-48", "40-80", "60-105", "110-130", "75-400"]
r = [tuple(map(int, z.split("-"))) for z in r]

# [(12, 48), (40, 80), (60, 105), (110, 130), (75, 400)]

然后,我迭代所有范围并删除任何完全被另一个范围封装的范围。例如:(110, 130)(75, 400) 内:

hold = []
for idx1 in range(len(r)):
    start_1, stop_1 = r[idx1]
    for idx2, (start_2, stop_2) in enumerate(r):
        if idx1 == idx2:
            continue
        if start_2 < start_1 and stop_1 < stop_2:
            hold.append(idx1)

while hold:
    del r[hold.pop()]

# [(12, 48), (40, 80), (60, 105), (75, 400)]

最后,我使用pandas.DataFrame计算重叠和百分比重叠;标记符合排除标准的行(重叠 > 10 和 % > 0.2)。然后以相反的顺序删除这些行,并在每次删除后再次测试重叠,直到无法删除更多行。

然后,DataFrame 会被转换回字符串列表,格式与它们提供时的格式相同。

df = pd.DataFrame(r, columns=["start", "stop"]).sort_values("start")

df["length"] = df["stop"] - df["start"]
df["bool_1"], df["bool_2"] = True, True

while any(df["bool_1"].eq(True) & df["bool_2"].eq(True)):
    df["overlap"] = df["stop"] - df["start"].shift(-1)
    df["pc"] = df["overlap"] / df["length"]

    df["bool_1"] = df["overlap"] > 10
    df["bool_2"] = df["pc"] > 0.2
    for i, row in df.sort_index(ascending=False).iterrows():
        if row["bool_1"] == row["bool_2"] and row["bool_1"] is not False:
            df.drop(i, inplace=True)
            break

result = df["start"].astype("str").str.cat(df["stop"].astype("str"), sep="-").to_list()

# ['12-48', '40-80', '75-400']

【讨论】:

  • 抱歉耽搁了 - 这确实部分有效,但仍有一个实例失败。如果我们有一个诸如 [(0, 90), (27, 99), (28, 229), (126, 291), (138, 379)]] 的列表,它将过滤掉 0-90 而不是 27 -99。这意味着我们剩下 [(27-99),(138-379)] 作为剩余的范围列表。
  • 此外,它还应该删除任何两个“重叠”范围中最短的一个。
猜你喜欢
  • 2017-04-06
  • 2021-08-23
  • 1970-01-01
  • 2012-07-09
  • 1970-01-01
  • 2021-11-10
  • 1970-01-01
  • 1970-01-01
  • 2017-02-16
相关资源
最近更新 更多