Pandas groupby:使用其他列中的数据创建组(基因组间隔)

iyfjxgzm  于 10个月前  发布在  其他
关注(0)|答案(2)|浏览(72)

作为一个更大的数据集的一部分,我有一个DataFrame组织如下:

Chromosome    arm    Start    End    ratio_median
5    5.5    96100001    96150000    -0.582
5    5.5    96150001    96200000    -0.582
5    5.5    96200001    96250000    -0.582
5    5.5    96250001    96300000    -0.582
5    5.5    96300001    96350000    -0.582

字符串
这里的目标是将具有相同Chromosomearmratio_median的行分组,并使用最小值Start和最大值End形成更大的间隔。
这看起来像是一个可以用groupby解决的标准问题:

grouped = df.groupby(by=["Chromosome", "arm", "ratio_median"]).agg(
    {"Chromosome": "first", "Start": "min", "End": "max", "ratio_median": "first"})


然而,由于这些是坐标,分组应该只考虑具有共同分组键的连续组,而不是整个数据集。换句话说,当同一染色体和臂的ratio_median发生变化时,应该设置组边界。
groupby方法可以完美地工作,直到你有相同值的区间,这些区间被一个或多个不同键的区间分隔开(ratio_median是判别元素)。例如,从这些数据开始:

Chromosome    arm    Start    End    ratio_median
5    5.5    96150001    96200000    -0.582
5    5.5    96200001    96250000    -0.582
5    5.5    96250001    96300000    -0.582
5    5.5    96300001    96350000    -0.582
5    5.5    97000001    97050001    -0.582
5    5.5    102600001    102650000    -0.014
5    5.5    102650001    102700000    -0.014
5    5.5    102700001    102750000    -0.014
5    5.5    102750001    102800000    -0.014
5    5.5    102800001    102850000    -0.014
5    5.5    103700001    103750000    -0.582
5    5.5    103750001    103800000    -0.582
5    5.5    103800001    103850000    -0.582
5    5.5    103850001    103900000    -0.582
5    5.5    103900001    103950000    -0.582


这里有三个独立的间隔:但是使用groupby分组会将第三个间隔与第一个间隔合并(正确:它按预期工作):

Chromosome    arm    Start    End    ratio_median
5    5.5    96100001    103950000    -0.582
5    5.5    102600001    102850000    -0.014


从坐标的Angular 来看,这是不正确的,因为它们不应该像这样重叠:只有具有相同分组键的连续行才应该被聚合。正确的预期结果应该是:

Chromosome    arm    Start    End    ratio_median
5    5.5    96100001    97050001    -0.582
5    5.5    102600001    102850000    -0.014
5    5.5    103700001    103950000    -0.582


然而,我不知道如何在pandas中正确地做到这一点,也不知道如何使用额外的特定于域的库,如PyRangesbioframe。我已经尝试过PyRanges.cluster(),但另一方面,它以不同的方式分配ID,结果间隔较小。
我猜这里需要某种形式的迭代,但是最好的方法是什么呢?我已经单独尝试过groupby,但是同样受到上面问题的困扰。

7xzttuei

7xzttuei1#

您可以将每个分组的End与移动的Start进行比较,以形成一个新的分组器:

g = (df.sort_values(by=['Start', 'End'])
       .groupby(['Chromosome', 'arm', 'ratio_median'])['End']
       .transform(lambda s: s.shift().rsub(df['Start']).gt(1).cumsum())
    )

out = (df
   .groupby(['Chromosome', 'arm', 'ratio_median', g],
            as_index=False, sort=False)
   .agg({'Start': 'min', 'End': 'max'})
)

字符串
输出量:

Chromosome  arm  ratio_median      Start        End
0           5  5.5        -0.582   96150001   96350000
1           5  5.5        -0.014  102600001  102850000
2           5  5.5        -0.582  103700001  103950000


中间体:

Chromosome  arm      Start        End  ratio_median        sub  g
0            5  5.5   96150001   96200000        -0.582        NaN  0
1            5  5.5   96200001   96250000        -0.582        1.0  0
2            5  5.5   96250001   96300000        -0.582        1.0  0
3            5  5.5   96300001   96350000        -0.582        1.0  0
4            5  5.5  102600001  102650000        -0.014        NaN  0
5            5  5.5  102650001  102700000        -0.014        1.0  0
6            5  5.5  102700001  102750000        -0.014        1.0  0
7            5  5.5  102750001  102800000        -0.014        1.0  0
8            5  5.5  102800001  102850000        -0.014        1.0  0
9            5  5.5  103700001  103750000        -0.582  7350001.0  1
10           5  5.5  103750001  103800000        -0.582        1.0  1
11           5  5.5  103800001  103850000        -0.582        1.0  1
12           5  5.5  103850001  103900000        -0.582        1.0  1
13           5  5.5  103900001  103950000        -0.582        1.0  1


如果只想按选定列中的连续行进行分组:

cols = ['Chromosome', 'arm', 'ratio_median']
d = {c: 'first' for c in cols} | {'Start': 'min', 'End': 'max'}
out = df.groupby(df[cols].ne(df[cols].shift()).any(axis=1).cumsum()).agg(d)


输出量:

Chromosome  arm  ratio_median      Start        End
1           5  5.5        -0.582   96150001   97050001
2           5  5.5        -0.014  102600001  102850000
3           5  5.5        -0.582  103700001  103950000

zmeyuzjn

zmeyuzjn2#

@mozway提出的解决方案很接近,但在某些情况下不起作用,主要是因为我没有提到在具有相同比率的间隔中可以存在“间隙”(因此存在End和后续Start之间的差异> 1的情况)。
然而,建议的分组策略让我走上了正确的道路。我们需要用相同的比率对间隔进行分组,这样我们就可以在它发生变化时替换检查(observed被设置为True,因为在处理过程中进行的一些操作返回分类):

g = (
    df.groupby(['Chromosome', 'arm', 'ratio_median'],  
               observed=True)['ratio_median']
    .transform(
        lambda s: s.shift().rsub(df['ratio_median']).ne(0).cumsum()
    )
)
out = (df
   .groupby(['Chromosome', 'arm', 'ratio_median', g],
            as_index=False, sort=False)
   .agg({'Start': 'min', 'End': 'max'})
)

字符串
在我自己的数据集中,现在我发现数据是正确聚合的。

相关问题