Python PANDAS:使用 Groupby 重新采样多元时间序列

Posted

技术标签:

【中文标题】Python PANDAS:使用 Groupby 重新采样多元时间序列【英文标题】:Python PANDAS: Resampling Multivariate Time Series with a Groupby 【发布时间】:2018-03-18 14:35:00 【问题描述】:

我有以下一般格式的数据,我想重新采样到 30 天时间序列窗口:

'customer_id','transaction_dt','product','price','units'
1,2004-01-02,thing1,25,47
1,2004-01-17,thing2,150,8
2,2004-01-29,thing2,150,25
3,2017-07-15,thing3,55,17
3,2016-05-12,thing3,55,47
4,2012-02-23,thing2,150,22
4,2009-10-10,thing1,25,12
4,2014-04-04,thing2,150,2
5,2008-07-09,thing2,150,43

我希望 30 天的窗口期从 2014 年 1 月 1 日开始,到 2018 年 12 月 31 日结束。不保证每个客户都会在每个窗口中都有记录。如果客户在一个窗口中有多个交易,那么它会采用价格的加权平均值,对单位求和,然后连接产品名称,从而为每个窗口的每个客户创建一条记录。

到目前为止,我所拥有的是这样的:

wa = lambda x:np.average(x, weights=df.loc[x.index, 'units'])
con = lambda x: '/'.join(x))

agg_funcs = 'customer_id':'first',
             'product':'con',
             'price':'wa',
             'transaction_dt':'first',
             'units':'sum'

df_window = df.groupby(['customer_id', pd.Grouper(freq='30D')]).agg(agg_funcs)
df_window_final = df_window.unstack('customer_id', fill_value=0)

如果有人知道一些更好的方法来解决这个问题(特别是使用就地和/或矢量化方法),我将不胜感激。理想情况下,我还想将窗口开始日期和停止日期作为列添加到行中。

理想的最终输出如下所示:

'customer_id','transaction_dt','product','price','units','window_start_dt','window_end_dt'
1,2004-01-02,thing1/thing2,(weighted average price),(total units),(window_start_dt),(window_end_dt)
2,2004-01-29,thing2,(weighted average price),(total units),(window_start_dt),(window_end_dt)
3,2017-07-15,thing3,(weighted average price),(total units),(window_start_dt),(window_end_dt)
3,2016-05-12,thing3,(weighted average price),(total units),(window_start_dt),(window_end_dt)
4,2012-02-23,thing2,(weighted average price),(total units),(window_start_dt),(window_end_dt)
4,2009-10-10,thing1,(weighted average price),(total units),(window_start_dt),(window_end_dt)
4,2014-04-04,thing2,(weighted average price),(total units),(window_start_dt),(window_end_dt)
5,2008-07-09,thing2,(weighted average price),(total units),(window_start_dt),(window_end_dt)

【问题讨论】:

加权平均价格需要一个权重来进行平均。重量是多少。而且,为了不产生歧义,最终结果应该是什么样子,以便决定帮助的人在提交答案之前有一些可比较的东西。 对不起,如果混淆了,这应该是根据 groupby 期间窗口中的单位总数计算加权平均价格:wa = lambda x:np.average(x, weights= df.loc[x.index, 'units']) 价格权重为 (# of) 个单位。 【参考方案1】:

针对新解决方案进行了编辑。我认为您可以将每个 transaction_dt 转换为 30 天的 Period 对象,然后进行分组。

p = pd.period_range('2004-1-1', '12-31-2018',freq='30D')
def find_period(v):
    p_idx = np.argmax(v < p.end_time)
    return p[p_idx]
df['period'] = df['transaction_dt'].apply(find_period)
df

   customer_id transaction_dt product  price  units     period
0            1     2004-01-02  thing1     25     47 2004-01-01
1            1     2004-01-17  thing2    150      8 2004-01-01
2            2     2004-01-29  thing2    150     25 2004-01-01
3            3     2017-07-15  thing3     55     17 2017-06-21
4            3     2016-05-12  thing3     55     47 2016-04-27
5            4     2012-02-23  thing2    150     22 2012-02-18
6            4     2009-10-10  thing1     25     12 2009-10-01
7            4     2014-04-04  thing2    150      2 2014-03-09
8            5     2008-07-09  thing2    150     43 2008-07-08

我们现在可以使用此数据框来获取产品的串联、价格的加权平均值和单位总和。然后我们使用一些 Period 功能来获取结束时间。

def my_funcs(df):
    data = 
    data['product'] = '/'.join(df['product'].tolist())
    data['units'] = df.units.sum()
    data['price'] = np.average(df['price'], weights=df['units'])
    data['transaction_dt'] = df['transaction_dt'].iloc[0]
    data['window_start_time'] = df['period'].iloc[0].start_time
    data['window_end_time'] = df['period'].iloc[0].end_time
    return pd.Series(data, index=['transaction_dt', 'product', 'price','units', 
                                  'window_start_time', 'window_end_time'])

df.groupby(['customer_id', 'period']).apply(my_funcs).reset_index('period', drop=True)

【讨论】:

这是一个非常优雅的解决方案!谢谢!对于读者,我还提出了一种方法,使用一系列 groupby/transforms 来创建新值,然后是最终的 groupby,它更快但消耗更多内存,因为它不是原位的。 我最近又重温了一遍。不幸的是,我不确定 my_funcs 中的 'window_start_time' 和 'window_end_time' 是否正常工作。它似乎只为我返回最近 30 天的窗口日期。

以上是关于Python PANDAS:使用 Groupby 重新采样多元时间序列的主要内容,如果未能解决你的问题,请参考以下文章

使用 selection & groupby (python) 维护 pandas df 索引

python pandas groupby分组后的数据怎么用

python – Pandas使用groupby中的count来创建新列

python [groupby]示例groupby #pandas #secret

Python PANDAS:使用 Groupby 重新采样多元时间序列

使用 pandas python 将 2 个 groupby 输出与 lambda 组合