按组计算平均值,但保留所有列。

5

我希望使用groupby计算数值列的平均值,但是要保留所有列。以下是一个包含7列的数据框示例:

跟踪ID 基因ID 基因简称 TSS_ID 区域 FPKM-1 FPKM-2 ENSMUSG00000025902 ENSMUSG00000025902 Sox17 Tss1231 1:4490927-4496413 0.611985 232 ENSMUSG00000025902 ENSMUSG00000025902 Sox17 Ts412 1:4490927-4496413 12 21 ENSMUSG00000025902 ENSMUSG00000025902 Sox17 Ts56 1:4490927-4496413 2 213 ENSMUSG00000025902 ENSMUSG00000025902 Sox17 TS512 1:4490927-4496413 0.611985 5 ENSMUSG00000025902 ENSMUSG00000025902 Sox17 TS12241 1:4490927-4496413 0.611985 51 ENSMUSG00000096126 ENSMUSG00000096126 Gm22307 TS124 1:4529016-4529123 35 1 ENSMUSG00000096126 ENSMUSG00000096126 Gm22307 TS-1824 1:4529016-4529123 1 2 ENSMUSG00000096126 ENSMUSG00000096126 Gm22307 TS1249082 1:4529016-4529123 2 5 ENSMUSG00000088000 ENSMUSG00000088000 Gm25493 TS1290328 1:4723276-4723379 0 1 ENSMUSG00000098104 ENSMUSG00000098104 Gm6085 TS01239-1 1:4687933-4689403 0.0743559 6 ENSMUSG00000033845 ENSMUSG00000033845 Mrpl15 TSS31014,TSS82987,TSS82990,TSS86849 1:4773205-4785739 79.1154 7 ENSMUSG00000093015 ENSMUSG00000093015 Gm22463 TSS79849 1:5644644-5644745 0 1 ENSMUSG00000025905 ENSMUSG00000025905 Oprk1 TSS15316,TSS3878,TSS6226,TSS65522 1:5588492-5606131 0 6 ENSMUSG00000033774 ENSMUSG00000033774 Npbwr1 TSS69693 1:5913706-5917398 0 8 ENSMUSG00000033793 ENSMUSG00000033793 Atp6v1h TSS4651 1:5083172-5162549 24.2386 9 ENSMUSG00000087247 ENSMUSG00000087247 Fam150a TSS42747 1:6359330-6394731 0.502804 1
我希望能按照前三列进行分组,并在输出中保留第四和第五列(最好是每个重复的1到3列的第一行),然后计算数值列的平均值。我已经写了以下代码:
import pandas as pd
df = pd.read_table('grouping.txt')
grouped = df.groupby(list(df.columns[0:3]), sort=False).mean()

输出结果如下所示:
跟输入文件相比,输出结果中缺少第四列(TSS)和第五列(locus)。我该怎么保留这两列呢?由于它们的值是不同的,因此不能将它们作为groupby列的一部分。只要其中一个groupby列存在,保留这两个列中的任何一个值都可以。
2个回答

11
您可以将groupby()聚合的结果与您原始DataFrame中去重后的版本合并。可能会像这样:
# identify the columns we want to aggregate by; this could
# equivalently be defined as list(df.columns[0:3])
group_cols = ['tracking_id', 'gene_id', 'gene_short_name']
# identify the columns which we want to average; this could
# equivalently be defined as list(df.columns[4:])
metric_cols = ['FPKM-1', 'FPKM-2']

# create a new DataFrame with a MultiIndex consisting of the group_cols
# and a column for the mean of each column in metric_cols
aggs = df.groupby(group_cols)[metric_cols].mean()
# remove the metric_cols from df because we are going to replace them
# with the means in aggs
df.drop(metric_cols, axis=1, inplace=True)
# dedupe to leave only one row with each combination of group_cols
# in df
df.drop_duplicates(subset=group_cols, keep='last', inplace=True)
# add the mean columns from aggs into df
df = df.merge(right=aggs, right_index=True, left_on=group_cols, how='right')

2
输出结果与输入相同,只是最后一列被替换成了平均值。不认为它有效。 - BioProgram
@BioProgram - 我误解了你的问题。我更新了我的答案,提供了另一种可能的方法... - SPKoder
你的脚本可用。能否请你解释一下reset_index,然后是列的置顶操作。我无法理解第3、4和5行实际上正在做什么。另外,你编写的groupby()[].mean()的方式与我编写的有所不同..不确定它如何仍然有效。如果你能详细说明一下就太感谢了。 - BioProgram
顺便说一下,“take_last=True” 应该改为 “keep='last'”。 - BioProgram
1
我已经添加了一些注释。希望这样能更清晰明了。在 groupby() 行中的 [metric_cols] 不是必需的,但我认为它可以使代码更整洁。它明确指定了哪些列将被平均,而不是让 Pandas 简单地平均所有数值列。 - SPKoder
是的 - 现在更推荐使用 keep='last'。我仍然在使用旧版本的 pandas :-) - SPKoder

8
您可以使用函数字典进行聚合,每个字典项对应一列数据。代码中使用lambda表达式以及Pandas(dataframe)函数的字符串版本,这样Pandas会自动获取平均值(mean())。请参考链接
grouped = df.groupby(list(df.columns[0:3]), sort=False).agg(
    {'FPKM-1': 'mean', 'FPKM-2': 'mean',
     'tss_id': lambda x: x.iloc[0], 'locus': lambda x: x.iloc[0]})
print(grouped)

提供:

tracking_id        gene_id            gene_short_name                               tss_id     FPKM-1      FPKM-2              locus
ENSMUSG00000025902 ENSMUSG00000025902 Sox17                                        Tss1231   3.167191  104.400000  1:4490927-4496413
ENSMUSG00000096126 ENSMUSG00000096126 Gm22307                                        TS124  12.666667    2.666667  1:4529016-4529123
ENSMUSG00000088000 ENSMUSG00000088000 Gm25493                                    TS1290328   0.000000    1.000000  1:4723276-4723379
ENSMUSG00000098104 ENSMUSG00000098104 Gm6085                                     TS01239-1   0.074356    6.000000  1:4687933-4689403
ENSMUSG00000033845 ENSMUSG00000033845 Mrpl15           TSS31014,TSS82987,TSS82990,TSS86849  79.115400    7.000000  1:4773205-4785739
ENSMUSG00000093015 ENSMUSG00000093015 Gm22463                                     TSS79849   0.000000    1.000000  1:5644644-5644745
ENSMUSG00000025905 ENSMUSG00000025905 Oprk1              TSS15316,TSS3878,TSS6226,TSS65522   0.000000    6.000000  1:5588492-5606131
ENSMUSG00000033774 ENSMUSG00000033774 Npbwr1                                      TSS69693   0.000000    8.000000  1:5913706-5917398
ENSMUSG00000033793 ENSMUSG00000033793 Atp6v1h                                      TSS4651  24.238600    9.000000  1:5083172-5162549
ENSMUSG00000087247 ENSMUSG00000087247 Fam150a                                     TSS42747   0.502804    1.000000  1:6359330-6394731

谢谢,那个可行,除了一个问题。最后的FPKM-1..列可能会多达1000列。但它总是在第5列(位点)之后。此外,在您的脚本中,位点列似乎已经移到了末尾。我如何才能让均值计算完成而不必重复1000次并且保持位点列在其应该在的位置? - BioProgram
您可以通过字典推导式在程序中创建字典,其中包括相关列。定位列对于计算并不重要,这只是观察者的看法;您可以按照必要的顺序指定列作为索引传递给grouped[list_of_column_names_in_order'] - user707650

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