Python 如何通过比较值的范围来合并两个数据帧(或传输值)

Python 如何通过比较值的范围来合并两个数据帧(或传输值),python,pandas,dataframe,merge,bioinformatics,Python,Pandas,Dataframe,Merge,Bioinformatics,在以下数据中: data01 = contig start end haplotype_block 2 5207 5867 1856 2 155667 155670 2816 2 67910 68022 2 2 68464 68483 3 2 525 775 132 2 118938 119559 1157 data02 = contig start last feature

在以下数据中:

data01 =

contig  start    end    haplotype_block 
2   5207    5867    1856
2   155667    155670    2816
2   67910    68022  2
2   68464    68483  3
2   525    775  132
2   118938    119559    1157

data02 =

contig    start   last    feature gene_id gene_name   transcript_id
2   5262    5496    exon    scaffold_200003.1   CP5 scaffold_200003.1
2   5579    5750    exon    scaffold_200003.1   CP5 scaffold_200003.1
2   5856    6032    exon    scaffold_200003.1   CP5 scaffold_200003.1
2   6115    6198    exon    scaffold_200003.1   CP5 scaffold_200003.1
2   916 1201    exon    scaffold_200001.1   NA  scaffold_200001.1
2   614 789 exon    scaffold_200001.1   NA  scaffold_200001.1
2   171 435 exon    scaffold_200001.1   NA  scaffold_200001.1
2   2677    2806    exon    scaffold_200002.1   NA  scaffold_200002.1
2   2899    3125    exon    scaffold_200002.1   NA  scaffold_200002.1
问题:

  • 我想比较这两个数据帧的范围(开始-结束)
  • 如果范围重叠,我想将
    gene_id
    gene_name
    值从data02传输到data01中的新列
我试过(用熊猫):


我知道您正在使用python,但使用经典的生物信息学工具
bedtools intersect
,您的问题可能很容易解决:

您的两个输入文件均采用标准BED格式:


Bedtools intersect为您提供了如何确定两个区域之间的交点或重叠的高级逻辑。我相信它也可以直接操作bgzipped输入

你应该在python中使用区间树函数,它们非常高效且内存友好,我尝试了类似的方法,并将其运行到某个问题上,该问题后来得到了解决,但下面是我编写的代码,

您可以在此代码的基础上进行构建

s1=data01.start.values
s1 = data01.start.values
e1 = data01.end.values
s2 = data02.start.values
e2 = data02['last'].values

overlap = (
    (s1[:, None] <= s2) & (e1[:, None] >= s2)
) | (
    (s1[:, None] <= e2) & (e1[:, None] >= e2)
)

g = data02.gene_id.values
n = data02.gene_name.values

i, j = np.where(overlap)
idx_map = {i_: data01.index[i_] for i_ in pd.unique(i)}

def make_series(m):
    s = pd.Series(m[j]).fillna('').groupby(i).agg(','.join)
    return s.rename_axis(idx_map).replace('', np.nan)

data01.assign(
    gene_id=make_series(g),
    gene_name=make_series(n),
)
e1=data01.end.values s2=data02.start.values e2=data02['last'].值 重叠=( (s1[:,无]=s2) ) | ( (s1[:,无]=e2) ) g=data02.gene\U id.values n=data02.gene\u name.values i、 j=np.其中(重叠) idx_map={i_U1;:data01.index[i_U1;]用于pd.unique(i)} def make_系列(m): s=pd.Series(m[j]).fillna(“”).groupby(i).agg(‘,’.join) 返回s.rename_轴(idx_映射)。替换(“”,np.nan) data01.assign( gene_id=make_系列(g), 基因名称=制造系列(n), )

如果您想要比bedtools快得多的东西和/或Python science stack的本地居民想要的东西,请尝试:


我以前用过床上工具。由于
start-end
值的原因,我的数据是bed格式的,但我不确定是否有效,是否能够传输这些值(完全按照我的要求)。我已经使用python、pandas、list、dict有一段时间了,使用这些工具来完成特定的任务感觉更好。标准的生物信息学工具很好(如bwa、vcf文件等),但当它变得过于具体时,这些工具变得非常烦人而不是有用。我只是重新访问了bedtools。出于我的目的,我最好使用python和pandas(else字典)。原因是我所做的是大管道的一部分,而引入bedtools只会让事情变得复杂而不是简单。不过,你可能有其他想法/意见。如果有的话,我将不胜感激。ThanksBedtools是为解决您的问题而开发的,这是生物信息学中的一个常见问题。算法本身可能有些细微差别,特别是如果您希望它高效的话。我建议您在开始重新实现该算法之前先尝试一下。;)唯一对我有用的方法是
bedtools intersect
,它将使我丢失data01中的数据,或者
bedtools merge
,但我只想更新data01中的列值,而不是合并所有信息。我不确定。我打算花些时间在
bedtools
上,否则,如果它不起作用,我在python的利基中就太舒服了。哈哈。我不会担心来自
bedtools merge
的额外列。床上工具会很快。您可以将结果加载到pandas中,然后向下选择感兴趣的列。谢谢,我会研究它。我不知道目标是什么。如果你能说出你的输出是什么样子的,我很乐意再看一眼。@piRSquared:刚刚添加了所需的输出。我希望这是有道理的。解决这个问题的更好方法是先在两个数据帧上进行conting和start排序(以防止大量for循环),我已经这样做了;但不在上述数据01和数据02中。
contig  start    end    haplotype_block    gene_id    gene_name
2   5207    5867    1856    scaffold_200003.1,scaffold_200003.1,scaffold_200003.1   CP5,CP5,CP5

# the gene_id and gene_name are repeated 3 times because three intervals (i.e 5262-5496, 5579-5750, 5856-6032) from data02 overlap(or touch) the interval ranges from data01 (5207-5867)

# So, whenever there is overlap of the ranges between two dataframe, copy the gene_id and gene_name.

# and simply NA on gene_id and gene_name for non overlapping ranges

2   155667    155670    2816    NA    NA
2   67910    68022  2    NA    NA
2   68464    68483  3    NA    NA
2   525    775  132    scaffold_200001.1   NA
2   118938    119559    1157    NA    NA
s1 = data01.start.values
e1 = data01.end.values
s2 = data02.start.values
e2 = data02['last'].values

overlap = (
    (s1[:, None] <= s2) & (e1[:, None] >= s2)
) | (
    (s1[:, None] <= e2) & (e1[:, None] >= e2)
)

g = data02.gene_id.values
n = data02.gene_name.values

i, j = np.where(overlap)
idx_map = {i_: data01.index[i_] for i_ in pd.unique(i)}

def make_series(m):
    s = pd.Series(m[j]).fillna('').groupby(i).agg(','.join)
    return s.rename_axis(idx_map).replace('', np.nan)

data01.assign(
    gene_id=make_series(g),
    gene_name=make_series(n),
)
import pyranges as pr

c1 = """Chromosome  Start    End    haplotype_block
2   5207    5867    1856
2   155667    155670    2816
2   67910    68022  2
2   68464    68483  3
2   525    775  132
2   118938    119559    1157"""

c2 = """Chromosome Start End  feature gene_id gene_name   transcript_id
2   5262    5496    exon    scaffold_200003.1   CP5 scaffold_200003.1
2   5579    5750    exon    scaffold_200003.1   CP5 scaffold_200003.1
2   5856    6032    exon    scaffold_200003.1   CP5 scaffold_200003.1
2   6115    6198    exon    scaffold_200003.1   CP5 scaffold_200003.1
2   916 1201    exon    scaffold_200001.1   NA  scaffold_200001.1
2   614 789 exon    scaffold_200001.1   NA  scaffold_200001.1
2   171 435 exon    scaffold_200001.1   NA  scaffold_200001.1
2   2677    2806    exon    scaffold_200002.1   NA  scaffold_200002.1
2   2899    3125    exon    scaffold_200002.1   NA  scaffold_200002.1"""

gr1, gr2 = pr.from_string(c1), pr.from_string(c2)

j = gr1.join(gr2).sort()

print(j)
# +--------------+-----------+-----------+-------------------+-----------+-----------+------------+-------------------+-------------+-------------------+
# |   Chromosome |     Start |       End |   haplotype_block |   Start_b |     End_b | feature    | gene_id           | gene_name   | transcript_id     |
# |   (category) |   (int32) |   (int32) |           (int64) |   (int32) |   (int32) | (object)   | (object)          | (object)    | (object)          |
# |--------------+-----------+-----------+-------------------+-----------+-----------+------------+-------------------+-------------+-------------------|
# |            2 |       525 |       775 |               132 |       614 |       789 | exon       | scaffold_200001.1 | nan         | scaffold_200001.1 |
# |            2 |      5207 |      5867 |              1856 |      5262 |      5496 | exon       | scaffold_200003.1 | CP5         | scaffold_200003.1 |
# |            2 |      5207 |      5867 |              1856 |      5579 |      5750 | exon       | scaffold_200003.1 | CP5         | scaffold_200003.1 |
# |            2 |      5207 |      5867 |              1856 |      5856 |      6032 | exon       | scaffold_200003.1 | CP5         | scaffold_200003.1 |
# +--------------+-----------+-----------+-------------------+-----------+-----------+------------+-------------------+-------------+-------------------+
# Unstranded PyRanges object has 4 rows and 10 columns from 1 chromosomes.
# For printing, the PyRanges was sorted on Chromosome.

print(j.df)
#   Chromosome  Start   End  haplotype_block  Start_b  End_b feature            gene_id gene_name      transcript_id
# 0          2    525   775              132      614    789    exon  scaffold_200001.1       NaN  scaffold_200001.1
# 1          2   5207  5867             1856     5262   5496    exon  scaffold_200003.1       CP5  scaffold_200003.1
# 2          2   5207  5867             1856     5579   5750    exon  scaffold_200003.1       CP5  scaffold_200003.1
# 3          2   5207  5867             1856     5856   6032    exon  scaffold_200003.1       CP5  scaffold_200003.1