Python 3.x 为什么在pandas行中使用列表作为值允许我动态更新?

Python 3.x 为什么在pandas行中使用列表作为值允许我动态更新?,python-3.x,pandas,loops,aggregate-functions,bioinformatics,Python 3.x,Pandas,Loops,Aggregate Functions,Bioinformatics,我有一些行为我不明白。如果有人能解释一下为什么这会起作用,并给我展示一个更好的方法,那就太好了,它变得非常复杂 我的目标是将给定染色体上相邻的基因变体连接起来。这将发现任何长度不超过5 bp(位置)的变体组合。这意味着,如果有5个位置彼此相邻,则应将它们全部连接起来,然后不应再次检查这些位置。然后,长度为4、3、2的组合也是如此。我用这行代码“for var_len in[5,4,3,2,1]:”来处理这个问题,并且集合已经更新了。此解决方案有效,但前提是我将“肿瘤”放在df的列表中。为什么呢?

我有一些行为我不明白。如果有人能解释一下为什么这会起作用,并给我展示一个更好的方法,那就太好了,它变得非常复杂

我的目标是将给定染色体上相邻的基因变体连接起来。这将发现任何长度不超过5 bp(位置)的变体组合。这意味着,如果有5个位置彼此相邻,则应将它们全部连接起来,然后不应再次检查这些位置。然后,长度为4、3、2的组合也是如此。我用这行代码“for var_len in[5,4,3,2,1]:”来处理这个问题,并且集合已经更新了。此解决方案有效,但前提是我将“肿瘤”放在df的列表中。为什么呢?有人能告诉我如何在不使用迭代的情况下获得相同的输出吗

df = pd.DataFrame([['chr1',13,['A']],
              ['chr1',5,['A']],
              ['chr1',6,['G']],
              ['chr2',9,['G']],
               ['chr1',4,['C']],
              ['chr1',11,['T']]],
              columns=['chrom','pos','tumour_alts'],
             index=['chr1:13','chr1:5','chr1:6','chr2:9','chr1:4','chr1:11'])
already_updated = set([])
for chrom, df_tmp in df.groupby('chrom'):
    df_tmp = df_tmp.sort_values(by=['pos'])
    for var_len in [5, 4, 3, 2, 1]:
        df_tmp['dif'] = df_tmp.pos.diff(var_len)
        hits=df_tmp[df_tmp['dif'] == var_len]
        for hit in hits.pos:
            rows = df_tmp[(df_tmp.pos <= hit) & (df_tmp.pos >= (hit - var_len))]
            update = dict(rows.iloc[0])
            for i in range(var_len):
                i+=1
                update_tmp = dict(rows.iloc[i])
                key = update_tmp.get('chrom') + ':'+str(update_tmp.get('pos'))
                if key not in already_updated:
                    df = df.drop(index=(key))
                    update['tumour_alts'][0]+=update_tmp.get('tumour_alts')[0]
                    already_updated.add(key)


df

chrom   pos tumour_alts
chr1:13 chr1    13  [A]
chr2:9  chr2    9   [G]
chr1:4  chr1    4   [CAG]
chr1:11 chr1    11  [T]
我期望:

chrom   pos tumour_alts
chr1:3  chr1    3   [ACAG]
chr1:11 chr1    11  [T]
chr1:13 chr1    13  [A]
chr1:55 chr1    55  [AG]
chr2:9  chr2    9   [G]
chr2:95 chr2    95  [G]

您可以尝试使用groupby而不是for循环。此外,我不确定您所说的“这应该会找到任何长度不超过5 bp(位置)的变体组合”是什么意思,因此我没有将其包含在下面的代码中

# remove characters from list
df['tumour_alts'] = df['tumour_alts'].astype(str).str.replace("\[|\]", '').str.replace("'", '')
# sort values
df = df.sort_values('pos')
# groupby chrom (assuming you need to group these together)
g = df.groupby('chrom')['pos']
# check the value above and below to see if they are == eachother
mask = ~((g.shift(0) == g.shift(-1)-1) | (g.shift(0) == g.shift(1)+1))
# use cumsum to assign a number value for each group
gr = mask.cumsum()-mask.cumsum().where(~mask).ffill().fillna(0).astype(int)
# groupby gr and transform with sum to append strings together
s = df.groupby(gr)['tumour_alts'].transform(sum).drop_duplicates(keep='first').to_frame()
# drop column and merge right
df.drop(columns='tumour_alts').merge(s, left_index=True, right_index=True, how='right')

        chrom  pos tumour_alts
chr1:4   chr1    4         CAG
chr2:9   chr2    9           G
chr1:11  chr1   11           T
chr1:13  chr1   13           A
虽然上面的代码确实产生了您的预期输出,但我对染色体了解不多,因此
删除重复项
可能不合适。您可能希望将所有内容合并在一起,然后根据适当的参数删除行

# remove characters from list
df['tumour_alts'] = df['tumour_alts'].astype(str).str.replace("\[|\]", '').str.replace("'", '')
# sort values
df = df.sort_values('pos')
# groupby chrom (assuming you need to group these together)
g = df.groupby('chrom')['pos']
# check the value above and below to see if the are == eachother
mask = ~((g.shift(0) == g.shift(-1)-1) | (g.shift(0) == g.shift(1)+1))
# use cumsum to assign a number value for each group
gr = mask.cumsum()-mask.cumsum().where(~mask).ffill().fillna(0).astype(int)
# groupby gr and transform with sum to append strings together
s = df.groupby(gr)['tumour_alts'].transform(sum).to_frame()
# merge right
df.merge(s, left_index=True, right_index=True, how='right')

        chrom  pos tumour_alts_x tumour_alts_y
chr1:4   chr1    4             C           CAG
chr1:5   chr1    5             A           CAG
chr1:6   chr1    6             G           CAG
chr2:9   chr2    9             G             G
chr1:11  chr1   11             T             T
chr1:13  chr1   13             A             A

您可以尝试使用groupby而不是for循环。此外,我不确定您所说的“这应该会找到任何长度不超过5 bp(位置)的变体组合”是什么意思,因此我没有将其包含在下面的代码中

# remove characters from list
df['tumour_alts'] = df['tumour_alts'].astype(str).str.replace("\[|\]", '').str.replace("'", '')
# sort values
df = df.sort_values('pos')
# groupby chrom (assuming you need to group these together)
g = df.groupby('chrom')['pos']
# check the value above and below to see if they are == eachother
mask = ~((g.shift(0) == g.shift(-1)-1) | (g.shift(0) == g.shift(1)+1))
# use cumsum to assign a number value for each group
gr = mask.cumsum()-mask.cumsum().where(~mask).ffill().fillna(0).astype(int)
# groupby gr and transform with sum to append strings together
s = df.groupby(gr)['tumour_alts'].transform(sum).drop_duplicates(keep='first').to_frame()
# drop column and merge right
df.drop(columns='tumour_alts').merge(s, left_index=True, right_index=True, how='right')

        chrom  pos tumour_alts
chr1:4   chr1    4         CAG
chr2:9   chr2    9           G
chr1:11  chr1   11           T
chr1:13  chr1   13           A
虽然上面的代码确实产生了您的预期输出,但我对染色体了解不多,因此
删除重复项
可能不合适。您可能希望将所有内容合并在一起,然后根据适当的参数删除行

# remove characters from list
df['tumour_alts'] = df['tumour_alts'].astype(str).str.replace("\[|\]", '').str.replace("'", '')
# sort values
df = df.sort_values('pos')
# groupby chrom (assuming you need to group these together)
g = df.groupby('chrom')['pos']
# check the value above and below to see if the are == eachother
mask = ~((g.shift(0) == g.shift(-1)-1) | (g.shift(0) == g.shift(1)+1))
# use cumsum to assign a number value for each group
gr = mask.cumsum()-mask.cumsum().where(~mask).ffill().fillna(0).astype(int)
# groupby gr and transform with sum to append strings together
s = df.groupby(gr)['tumour_alts'].transform(sum).to_frame()
# merge right
df.merge(s, left_index=True, right_index=True, how='right')

        chrom  pos tumour_alts_x tumour_alts_y
chr1:4   chr1    4             C           CAG
chr1:5   chr1    5             A           CAG
chr1:6   chr1    6             G           CAG
chr2:9   chr2    9             G             G
chr1:11  chr1   11             T             T
chr1:13  chr1   13             A             A

谢谢你的回答。我对我的问题进行了编辑,以进一步解释我的意思,即“这应该可以找到任何长度不超过5 bp(位置)的变体组合”。这意味着,如果有5个位置彼此相邻,则应将它们全部连接起来,然后不应再次检查这些位置。那么4,3,2也一样。我用这行代码“for var_len in[5,4,3,2,1]:”来处理这个问题,这个集合已经更新了。这是一个非常好的解决方案。我从中学到了很多。我试图对其进行修改,以适应问题中描述的日益增加的复杂性。掩模可以扩展以捕获多条线,例如“掩模=~((g.shift(0)=g.shift(-1)-1)|(g.shift(0)=g.shift(1)+1)|(g.shift(0)=g.shift(-2)-2)|(g.shift(0)=g.shift(2)+2))”。但是,“gr”行需要为要折叠的每个变体组合和不折叠的每个变体创建唯一的内容。有可能吗?谢谢你的回答。我对我的问题进行了编辑,以进一步解释我的意思,即“这应该可以找到任何长度不超过5 bp(位置)的变体组合”。这意味着,如果有5个位置彼此相邻,则应将它们全部连接起来,然后不应再次检查这些位置。那么4,3,2也一样。我用这行代码“for var_len in[5,4,3,2,1]:”来处理这个问题,这个集合已经更新了。这是一个非常好的解决方案。我从中学到了很多。我试图对其进行修改,以适应问题中描述的日益增加的复杂性。掩模可以扩展以捕获多条线,例如“掩模=~((g.shift(0)=g.shift(-1)-1)|(g.shift(0)=g.shift(1)+1)|(g.shift(0)=g.shift(-2)-2)|(g.shift(0)=g.shift(2)+2))”。但是,“gr”行需要为要折叠的每个变体组合和不折叠的每个变体创建唯一的内容。可能吗?