在pandas中执行聚合和重命名操作的惯用方法是什么?

时间:2017-07-28 20:44:31

标签: python pandas

例如,如何在pandas中执行以下R data.table操作:

PATHS[,.( completed=sum(exists), missing=sum(not(exists)), total=.N, 'size (G)'=sum(sizeMB)/1024), by=.(projectPath, pipelineId)]

即。按projectPathpipelineId分组,汇总了一些列 使用可能的自定义函数,然后重命名结果列。

输出应该是没有层次索引的DataFrame,例如:

                      projectPath pipelineId completed missing size (G)
/data/pnl/projects/TRACTS/pnlpipe          0      2568       0 45.30824
/data/pnl/projects/TRACTS/pnlpipe          1      1299       0 62.69934

2 个答案:

答案 0 :(得分:15)

您可以使用groupby.agg

df.groupby(['projectPath', 'pipelineId']).agg({
        'exists': {'completed': 'sum', 'missing': lambda x: (~x).sum(), 'total': 'size'},
        'sizeMB': {'size (G)': lambda x: x.sum()/1024}
    })

示例运行

df = pd.DataFrame({
        'projectPath': [1,1,1,1,2,2,2,2],
        'pipelineId': [1,1,2,2,1,1,2,2],
        'exists': [True, False,True,True,False,False,True,False],
        'sizeMB': [120032,12234,223311,3223,11223,33445,3444,23321]
    })

df1 = df.groupby(['projectPath', 'pipelineId']).agg({
        'exists': {'completed': 'sum', 'missing': lambda x: (~x).sum(), 'total': 'size'},
        'sizeMB': {'size (G)': lambda x: x.sum()/1024}
    })
​
df1.columns = df1.columns.droplevel(0)
​
df1.reset_index()

enter image description here

更新:如果您确实想要在不使用已弃用的嵌套字典语法的情况下自定义聚合,则始终可以使用groupby.apply并从中返回 Series 对象每个小组:

df.groupby(['projectPath', 'pipelineId']).apply(
    lambda g: pd.Series({
            'completed': g.exists.sum(),
            'missing': (~g.exists).sum(),
            'total': g.exists.size,
            'size (G)': g.sizeMB.sum()/1024 
        })
).reset_index()

enter image description here

答案 1 :(得分:1)

我相信新的0.20,更多"惯用"方式,就像这样(嵌套字典的第二层基本上被附加的.rename方法取代):

R中的

...( completed=sum(exists), missing=sum(not(exists)), total=.N, 'size (G)'=sum(sizeMB)/1024), by=.(projectPath, pipelineId)]...变为

编辑:在as_index=False中使用pd.DataFrame.groupby()来阻止最终df中的MultiIndex

df.groupby(['projectPath', 'pipelineId'], as_index=False).agg({
    'exists': 'sum', 
    'pipelineId': 'count', 
    'sizeMB': lambda s: s.sum() / 1024
}).rename(columns={'exists': 'completed', 
                   'pipelineId': 'total',
                   'sizeMB': 'size (G)'})

然后我可能会添加另一行来反对'存在' - > '缺失':

df['missing'] = df.total - df.completed
  

作为Jupyter笔记本测试中的一个示例,下面是pd.read_csv()导入Pandas DataFrame的46个总管道路径的模拟目录树,我稍微修改了相关示例以获得随机数据以1,000-100k核苷酸碱基之间的DNA串形式,代替产生Mb大小的文件。但是仍然计算非离散千兆基础,使用NumPy np.mean()pd.Series调用中df.agg调用的聚合lambda s: s.mean()对象进行详细说明,但df_paths.groupby(['TRACT', 'pipelineId']).agg({ 'mean_len(project)' : 'sum', 'len(seq)' : lambda agg_s: np.mean(agg_s.values) / 1e9 }).rename(columns={'len(seq)': 'Gb', 'mean_len(project)': 'TRACT_sum'}) 会是更简单的方法。

例如,

df_paths = pd.read_csv('./data/paths.txt', header=None, names=['projectPath'])
# df_paths['projectPath'] = 
df_paths['pipelineId'] = df_paths.projectPath.apply(
    lambda s: ''.join(s.split('/')[1:5])[:-3])
df_paths['TRACT'] = df_paths.pipelineId.apply(lambda s: s[:2])
df_paths['rand_DNA'] = [
    ''.join(random.choices(['A', 'C', 'T', 'G'], 
                           k=random.randint(1e3, 1e5)))
    for _ in range(df_paths.shape[0])
]
df_paths['len(seq)'] = df_paths.rand_DNA.apply(len)
df_paths['mean_len(project)'] = df_paths.pipelineId.apply(
    lambda pjct: df_paths.groupby('pipelineId')['len(seq)'].mean()[pjct])
df_paths

其中" TRACT"对于" pipelineId"是一个更高级别的类别。在目录树中,这样在这个例子中你可以看到共有46条独特的管道 - 2" TRACT"图层AB / AC x 6" pipelineId" /"项目"' sx 4二进制组合00,01,10,11(减去2个项目,GNU并行进入第三个topdir ; 见下文)。因此,在新的集合中,统计数据将项目级别的平均值转换为所有相应项目的总和,即每个TRACT。

enter image description here

wjm

enter image description here