Pythonic/Panda 方式创建 Groupby 函数

标签 python python-3.x pandas

我对编程相当陌生,正在寻找一种更Pythonic的方式来实现一些代码。这是虚拟数据:

 df = pd.DataFrame({
'Category':np.random.choice( ['Group A','Group B'], 10000),
'Sub-Category':np.random.choice( ['X','Y','Z'], 10000),
'Sub-Category-2':np.random.choice( ['G','F','I'], 10000),
'Product':np.random.choice( ['Product 1','Product 2','Product 3'], 10000),
'Units_Sold':np.random.randint(1,100, size=(10000)),
'Dollars_Sold':np.random.randint(100,1000, size=10000), 
'Customer':np.random.choice(pd.util.testing.rands_array(10,25,dtype='str'),10000),
'Date':np.random.choice( pd.date_range('1/1/2016','12/31/2018',  
                  freq='D'), 10000)})

我有很多事务数据,例如我在其上执行各种 Groupby 的数据。我当前的解决方案是制作一个像这样的主groupby:

master = df.groupby(['Customer','Category','Sub-Category','Product',pd.Grouper(key='Date',freq='A')])['Units_Sold'].sum()\
.unstack()

从那里,我使用 .groupby(level=) 函数执行各种分组,以我正在寻找的方式聚合信息。我通常会在每个级别上进行总结。此外,我使用以下代码的某些变体在每个级别创建小计。

y = master.groupby(level=[0,1,2]).sum()
y.index = pd.MultiIndex.from_arrays([
    y.index.get_level_values(0),
    y.index.get_level_values(1),
    y.index.get_level_values(2) + ' Total',
    len(y.index)*['']
])

y1 = master.groupby(level=[0,1]).sum()
y1.index = pd.MultiIndex.from_arrays([
    y1.index.get_level_values(0),
    y1.index.get_level_values(1)+ ' Total',
    len(y1.index)*[''],
    len(y1.index)*['']
])

y2 = master.groupby(level=[0]).sum()
y2.index = pd.MultiIndex.from_arrays([
    y2.index.get_level_values(0)+ ' Total',
    len(y2.index)*[''],
    len(y2.index)*[''],
    len(y2.index)*['']
])

pd.concat([master,y,y1,y2]).sort_index()\
    .assign(Diff = lambda x: x.iloc[:,-1] - x.iloc[:,-2])\
    .assign(Diff_Perc = lambda x: (x.iloc[:,-2] / x.iloc[:,-3])- 1)\
    .dropna(how='all')\

这只是一个示例 - 我可以执行相同的练习,但以不同的顺序执行 groupby。例如 - 接下来我可能想按“类别”、“产品”、然后“客户”进行分组,所以我必须这样做: master.groupby(level=[1,3,0).sum()

然后我将不得不重复上面的小计的整个练习。我还经常更改时间段 - 可能是年终某个特定月份,可能是年初至今,可能是按季度等。

根据我迄今为止在编程中学到的知识(显然,这是最少的!),您应该在每次重复代码时编写一个函数。显然,我在这个例子中一遍又一遍地重复代码。

有没有办法构建一个函数,您可以在其中向 Groupby 提供级别以及时间范围,同时创建一个用于对每个级别进行小计的函数?

预先感谢您对此的任何指导。这是非常赞赏。

最佳答案

对于 DRY-er 解决方案,请考虑将当前方法概括为已定义的模块,该模块按日期范围过滤原始数据帧并运行聚合,接收 group_by 级别和日期范围(后者是可选的)传入参数:

方法

def multiple_agg(mylevels, start_date='2016-01-01', end_date='2018-12-31'):

    filter_df = df[df['Date'].between(start_date, end_date)]

    master = (filter_df.groupby(['Customer', 'Category', 'Sub-Category', 'Product', 
                     pd.Grouper(key='Date',freq='A')])['Units_Sold']
                .sum()
                .unstack()
              )

    y = master.groupby(level=mylevels[:-1]).sum()
    y.index = pd.MultiIndex.from_arrays([
        y.index.get_level_values(0),
        y.index.get_level_values(1),
        y.index.get_level_values(2) + ' Total',
        len(y.index)*['']
    ])

    y1 = master.groupby(level=mylevels[0:2]).sum()
    y1.index = pd.MultiIndex.from_arrays([
        y1.index.get_level_values(0),
        y1.index.get_level_values(1)+ ' Total',
        len(y1.index)*[''],
        len(y1.index)*['']
    ])

    y2 = master.groupby(level=mylevels[0]).sum()
    y2.index = pd.MultiIndex.from_arrays([
        y2.index.get_level_values(0)+ ' Total',
        len(y2.index)*[''],
        len(y2.index)*[''],
        len(y2.index)*['']
    ])

    final_df = (pd.concat([master,y,y1,y2])
                         .sort_index()
                         .assign(Diff = lambda x: x.iloc[:,-1] - x.iloc[:,-2])
                         .assign(Diff_Perc = lambda x: (x.iloc[:,-2] / x.iloc[:,-3])- 1)
                         .dropna(how='all')
                         .reorder_levels(mylevels)
                )

    return final_df

聚合运行 (不同级别和日期范围)

agg_df1 = multiple_agg([0,1,2,3])

agg_df2 = multiple_agg([1,3,0,2], '2016-01-01', '2017-12-31')

agg_df3 = multiple_agg([2,3,1,0], start_date='2017-01-01', end_date='2018-12-31')

测试 (final_df 是 OP 的 pd.concat() 输出)

# EQUALITY TESTING OF FIRST 10 ROWS
print(final_df.head(10).eq(agg_df1.head(10)))

# Date                                        2016-12-31 00:00:00  2017-12-31 00:00:00  2018-12-31 00:00:00  Diff  Diff_Perc
# Customer   Category Sub-Category Product                                                                                  
# 45mhn4PU1O Group A  X            Product 1                 True                 True                 True  True       True
#                                  Product 2                 True                 True                 True  True       True
#                                  Product 3                 True                 True                 True  True       True
#                     X Total                                True                 True                 True  True       True
#                     Y            Product 1                 True                 True                 True  True       True
#                                  Product 2                 True                 True                 True  True       True
#                                  Product 3                 True                 True                 True  True       True
#                     Y Total                                True                 True                 True  True       True
#                     Z            Product 1                 True                 True                 True  True       True
#                                  Product 2                 True                 True                 True  True       True

关于Pythonic/Panda 方式创建 Groupby 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52208153/

相关文章:

python - 遍历和访问 JSON 中的内部元素

python - pandas 中数据的清理

python - 如何对 scipy.stats 测试实现多重测试

python - 将自动编码器权重绑定(bind)到密集的 Keras 层中

python - 在 Python 中将 QVariant 转换回 dict

python - 如何将 Python 与 Qlikview 连接起来进行数据可视化?

python - 在字典列表中添加元素

python - 使用 pandas 中的列进行回溯

python - 我们如何防止警告在其消息末尾打印奇怪的文本?

python - 从不同的 DataFrame 中减去值