将Pandas数据框转换为嵌套计数字典

3

我看到了很多有关如何将pandas数据框转换为嵌套字典的问题,但是没有一个涉及到信息聚合。 我甚至可能能够在pandas内完成我需要的操作,但是我卡住了。

输入

我有一个如下所示的数据框:

  FeatureID    gene  Target  pos  bc_count
0     1_1_1  NRAS_3  TAGCAC    0      0.42
1     1_1_1  NRAS_3  TGCACA    1      1.00
2     1_1_1  NRAS_3  GCACAA    2      0.50
3     1_1_1  NRAS_3  CACAAA    3      2.00
4     1_1_1  NRAS_3  CAGAAA    3      0.42

# create df as below
import pandas as pd
df = pd.DataFrame([{"FeatureID":"1_1_1", "gene":"NRAS_3", "Target":"TAGCAC", 
   "pos":0, "bc_count":.42},
   {"FeatureID":"1_1_1", "gene":"NRAS_3", "Target":"TGCACA", "pos":1, 
   "bc_count":1.00},
   {"FeatureID":"1_1_1", "gene":"NRAS_3", "Target":"GCACAA", "pos":2, 
   "bc_count":0.50},
   {"FeatureID":"1_1_1", "gene":"NRAS_3", "Target":"CACAAA", "pos":3, 
   "bc_count":2.00},
   {"FeatureID":"1_1_1", "gene":"NRAS_3", "Target":"CAGAAA", "pos":4, 
   "bc_count":0.42}])

问题

我需要将每一行的目标列分解,返回一个元组 (位置,字母,计数),其中起始位置在“pos”列中给出,然后枚举每个位置的字符串,计数是在该行中“bc_count”列中找到的值。

例如,在第一行中,期望的元组列表应为:

[(0, "T", 0.42), (1,"A", 0.42), (2,"G", 0.42), (3,"C", 0.42), (4,"A", 0.42), (5,"C", 0.42)]

我尝试过的

我编写了代码,将目标列分解为找到的位置,返回该字母的位置、核苷酸(字母)和计数的元组,并将它们作为一列添加到数据帧中:

def index_target(row):
    count_list = [((row.pos + x),y, 
        row.bc_count) for x,y in 
        enumerate(row.Target)]

df['pos_count'] = df.apply(self.index_target, axis=1)

该函数将基于行的目标列返回每一行的元组列表。

我需要处理df中的每一行,对于每个目标,计算其数量总和。因此,我考虑使用字典作为计数器:

position[letter] += bc_count

我尝试创建一个defaultdict,但它是将每个元组列表单独添加而不是对每个位置的计数进行求和:
from collections import defaultdict

d = defaultdict(dict) # also tried defaultdict(list) here
for x,y,z in row.pos_count:
    d[x][y] += z

预期输出

对于数据框中的每个特征,下面的数字代表在bc_count列中找到的每个位置的个体计数之和,x代表发现平局的位置,无法返回任何一个字母作为最大值:

pos A   T   G   C
0   25  80  25  57
1   32  19  100 32
2   27  18  16  27
3   90  90  90  90
4   10  42  37  18

共识= TGXXT


1
抱歉,但是有很多缺失的依赖项,而且不清楚如何从开始到结束。请尽量澄清您的问题。 - cs95
我已经提供了所有复现问题的代码,包括依赖项,并清楚地概述了我的期望输出。希望这样更清晰明了。 - SummerEla
@SummerEla,您所指的“期望输出”是否与您提供的示例输入相匹配?我的意思是,您的期望输出是否与您的数据框中得到的输出一致? - Edgar Ramírez Mondragón
2个回答

2

不确定如何获得您想要的输出,但我创建了一个包含元组的列表d,该列表可用于创建数据框。希望它能为您提供一些创建方向:

d = []

for t,c,p in zip(df.Target,df.bc_count,df.pos):
    d.extend([(p,c,i) for i in list(t)])

df_new = pd.DataFrame(d, columns = ['pos','count','val'])
df_new = df_new.groupby(['pos','val']).agg({'count':'sum'}).reset_index()

df_new.pivot(index = 'pos', columns = 'val', values = 'count')

2
这可能不是最优雅的解决方案,但我认为它可以实现您的需求:
new_df = pd.DataFrame(
    df.apply(
        # this lambda is basically the same thing you're doing,
        # but we create a pd.Series with it
        lambda row: pd.Series(
            [(row.pos + i, c, row.bc_count) for i, c in enumerate(row.Target)]
        ),
        axis=1)
        .stack().tolist(),
    columns=["pos", "nucl", "count"]

新的数据框 new_df 如下所示:

  pos nucl count
0   0    T  0.42
1   1    A  0.42
2   2    G  0.42
3   3    C  0.42
4   4    A  0.42
5   5    C  0.42
6   1    T  1.00
7   2    G  1.00
8   3    C  1.00
9   4    A  1.00

然后,我会进行数据透视以获取汇总计数:
nucleotide_count_by_pos = new_df.pivot_table(
    index="pos",
    columns="nucl",
    values="count",
    aggfunc="sum",
    fill_value=0
)

其中nucleotide_count_by_pos的格式如下:

nucl     A     C     G     T
 pos
   0  0.00  0.00  0.00  0.42
   1  0.42  0.00  0.00  1.00
   2  0.00  0.00  1.92  0.00
   3  0.00  4.34  0.00  0.00
   4  4.34  0.00  0.00  0.00

然后获得共识:

def get_consensus(row):
    max_value = row.max()
    nuc = row.idxmax()
    if (row == max_value).sum() == 1:
        return nuc
   else:
        return "X"

consensus = ''.join(nucleotide_count_by_pos.apply(get_consensus, axis=1).tolist())

在您的示例数据中,这将是:
'TTGCACAAA'

这太棒了。非常非常感谢! - SummerEla

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接