在 Python 中准确计算两个 DataFrame 之间的重叠和非重叠基因组区间

问题描述 投票:0回答:1

我想要 DF1 与 DF2 重叠的精确间隔。另外,我想要不与 DF2 重叠的间隔。这很棘手,因为您必须包括 A) 完全不重叠的 DF1 行 B) 部分重叠的 DF1 行。

可以看到DF1和DF2的第一行有重叠——重叠间隔(以DF1而言)是10-20。非重叠间隔(就 DF1 而言)为 1-9、21-100。当您考虑下一行时,另一个棘手的部分就出现了。非重叠区间为 1-59,如果我们只看这一行,这是正确的。但您必须确保所有间隔(无论是否重叠)在染色体水平上不会重叠。如果您还记得上面的行有一个从 10-20 的重叠区间,它与 1-59 重叠(因此 1-59 不是真正的非重叠区间)。 DF1 上的第二行与 DF2 没有重叠,因此您可以将整个间隔算作不重叠。

因此,对于1号染色体:重叠间隔为:10-20、60-100。

不重叠的间隔为1-9、21-59、150-200。

如您所见,要查看是否获得正确输出的真正测试是,如果将所有间隔(重叠和非重叠)相加,它应该等于 DF1 中区域的长度。

示例(为简单起见,忽略 2 号染色体):

DF1:1-100 + 150-200= 151 个碱基长(包括开始/结束)

1-9 = 9

10-20 = 11

21-59 = 39

60-100 = 41

150-200 = 51

9+11+39+41+51= 151 个碱基(匹配 DF1)

DF1

chr   start   end 
1     1       100
1     150     200
2     5       10

DF2

chr   start   end 
1     10      20
1     60      260
1     500     550
2     1       20
python pandas dataframe bioinformatics pyranges
1个回答
0
投票

IIUC你可以做这样的事情:

df1["range"] = df1.apply(lambda row: range(row["start"], row["end"] + 1), axis=1)
df1 = df1[["chr", "range"]].explode("range")


df2["range"] = df2.apply(lambda row: range(row["start"], row["end"] + 1), axis=1)
df2 = df2[["chr", "range"]].explode("range")

out = df1.merge(df2, on=["chr", "range"], how="outer", indicator=True)

out = out.groupby("chr").apply(
    lambda g: g.groupby((g["_merge"] != g["_merge"].shift()).cumsum()).agg(
        {"range": ["first", "last"], "_merge": "first"}
    ),
    include_groups=False,
)

print(out)

打印:

           range           _merge
           first last       first
chr _merge                       
1   1          1    9   left_only
    2         10   20        both
    3         21   59   left_only
    4         60  100        both
    5        101  149  right_only
    6        150  200        both
    7        201  550  right_only
2   1          1    4  right_only
    2          5   10        both
    3         11   20  right_only

结果包含所有区间,区间的“类型”位于

_merge
列中。例如
1-9
仅在
df1
中找到,
10-20
df1
中找到,
df2
中找到,
101-149
仅在
df2
等中找到。

© www.soinside.com 2019 - 2024. All rights reserved.