【问题标题】:Pandas group by then count & sum based on date range +/- x-daysPandas 分组然后根据日期范围 +/- x-days 计数和求和
【发布时间】:2018-08-31 12:12:41
【问题描述】:

在将数据框分组到某个列之后,我想在 +/- 7 天的时间内获得一个列的值的计数和总和

示例数据(经过编辑以反映我的真实数据集):

group  |        date          |   amount
-------------------------------------------
A      |  2017-12-26 04:20:20 |    50000.0
A      |  2018-01-17 00:54:15 |    60000.0
A      |  2018-01-27 06:10:12 |   150000.0
A      |  2018-02-01 01:15:06 |   100000.0
A      |  2018-02-11 05:05:34 |   150000.0
A      |  2018-03-01 11:20:04 |   150000.0
A      |  2018-03-16 12:14:01 |   150000.0
A      |  2018-03-23 05:15:07 |   150000.0
A      |  2018-04-02 10:40:35 |   150000.0

group分组,然后根据date-7求和datedate+7

我想要的结果:

group  |        date          |   amount    |  grouped_sum
-----------------------------------------------------------
A      |  2017-12-26 04:00:00 |    50000.0  |    50000.0
A      |  2018-01-17 00:00:00 |    60000.0  |    60000.0
A      |  2018-01-27 06:00:00 |   150000.0  |   250000.0
A      |  2018-02-01 01:00:00 |   100000.0  |   250000.0
A      |  2018-02-11 05:05:00 |   150000.0  |   150000.0
A      |  2018-03-01 11:00:04 |   150000.0  |   150000.0
A      |  2018-03-16 12:00:01 |   150000.0  |   150000.0
A      |  2018-03-23 05:00:07 |   100000.0  |   100000.0
A      |  2018-04-02 10:00:00 |   100000.0  |   100000.0

快速sn-p实现数据集:

group = 9 * ['A']
date = pd.to_datetime(['2017-12-26 04:20:20', '2018-01-17 00:54:15', 
                       '2018-01-27 06:10:12', '2018-02-01 01:15:06', 
                       '2018-02-11 05:05:34', '2018-03-01 11:20:04', 
                       '2018-03-16 12:14:01', '2018-03-23 05:15:07', 
                       '2018-04-02 10:40:35'])
amount = [50000.0, 60000.0, 150000.0, 100000.0, 150000.0, 
          150000.0, 150000.0, 150000.0, 150000.0]
df = pd.DataFrame({'group':group, 'date':date, 'amount':amount})

一点解释:

  • 第二行是 40,因为它汇总了 A 在 2018-01-14 和 2018-01-15 期间的数据
  • 第 4 行是 30,因为它汇总了 B 在 2018-01-03 + 未来 7 天期间的数据
  • 第 6 行是 30,因为它汇总了 B 在 2018 年 1 月 3 日 + 前 7 天期间的数据。

我不知道如何在一段日期范围内求和。如果我这样做,我也许可以做到:

1.创建另一列,每行显示 date-7 和 date+7

group  |    date     |  amount  |    date-7    |    date+7 
-------------------------------------------------------------
A      |  2017-12-26 |  50000.0 |  2017-12-19  |  2018-01-02
A      |  2018-01-17 |  60000.0 |  2018-01-10  |  2018-01-24

2.计算日期范围之间的金额:df[df.group == 'A' & df.date > df.date-7 & df.date < df.date+7].amount.sum()

3.但是这种方法相当繁琐。

编辑(2018-09-01): 根据@jezrael 的答案在下面找到了这个方法,它适用于我,但只适用于单个组:

t = pd.Timedelta(7, unit='d')
def g(row):
    res = df[(df.created > row.created - t) & (df.created < row.created + t)].amount.sum()
    return res

df['new'] = df.apply(g, axis=1)

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    这里是每行和每组的问题需要循环:

    t = pd.Timedelta(7, unit='d')
    
    def f(x):
        return x.apply(lambda y: x.loc[x['date'].between(y['date'] - t, 
                                                         y['date'] + t,
                                                         inclusive=False),'amount'].sum() ,axis=1)
    
    df['new'] = df.groupby('group', group_keys=False).apply(f)
    print (df)
      group       date  amount   new
    0     A 2018-01-01      10  10.0
    1     A 2018-01-14      20  40.0
    2     A 2018-01-15      20  40.0
    3     B 2018-02-03      10  30.0
    4     B 2018-02-04      10  30.0
    5     B 2018-02-05      10  30.0
    

    感谢@jpp 的改进:

    def f(x, t):
        return x.apply(lambda y: x.loc[x['date'].between(y['date'] - t, 
                                                         y['date'] + t,
                                                         inclusive=False),'amount'].sum(),axis=1)
    
    df['new'] = df.groupby('group', group_keys=False).apply(f, pd.Timedelta(7, unit='d'))
    

    验证解决方案:

    t = pd.Timedelta(7, unit='d')
    
    
    df = df[df['group'] == 'A']
    
    def test(y):
        a = df.loc[df['date'].between(y['date'] - t,  y['date'] + t,inclusive=False)]
        print (a)
        print (a['amount'])
        return a['amount'].sum()
    
      group       date  amount
    0     A 2018-01-01      10
    0    10
    Name: amount, dtype: int64
      group       date  amount
    1     A 2018-01-14      20
    2     A 2018-01-15      20
    1    20
    2    20
    Name: amount, dtype: int64
      group       date  amount
    1     A 2018-01-14      20
    2     A 2018-01-15      20
    1    20
    2    20
    Name: amount, dtype: int64
    
    df['new'] = df.apply(test,axis=1)
    print (df)
      group       date  amount  new
    0     A 2018-01-01      10   10
    1     A 2018-01-14      20   40
    2     A 2018-01-15      20   40
    

    【讨论】:

    • 不确定为什么它在这个数据集中有效,但它在我的原始数据集中无效。并非所有结果都是准确的。
    • @addicted - 你能解释更多吗?是否可以在失败的地方添加一些数据样本?
    • 不错的解决方案。在我看来,将t 作为参数传递给f() 是个好主意,这样会更清楚发生了什么。 GroupBy.apply 接受 argskwargs
    • @addicted - 添加测试解决方案 - 仅过滤一组并打印过滤后的值。
    • @addicted 我只有一个想法,有什么问题 - 尝试按 df =df. sort_values('group') 对真实数据中的组进行排序。是否可以匿名化真实数据集,例如。 G。由this 发送,如果仍然有问题并且验证解决方案不起作用,则将错误输出的数据集从配置文件发送到我的电子邮件?
    【解决方案2】:

    添加包含一周的第一天的列:

    df['week_start'] = df['date'].dt.to_period('W').apply(lambda x: x.start_time)
    

    结果:

      group       date  amount week_start
    0     A 2018-01-01      10 2017-12-26
    1     A 2018-01-14      20 2018-01-09
    2     A 2018-01-15      20 2018-01-09
    3     B 2018-02-03      10 2018-01-30
    4     B 2018-02-04      10 2018-01-30
    5     B 2018-02-05      10 2018-01-30
    

    按新列分组并查找每周总金额:

    grouped_sum = df.groupby('week_start')['amount'].sum().reset_index()
    

    结果:

      week_start  amount
    0 2017-12-26      10
    1 2018-01-09      40
    2 2018-01-30      30
    

    合并week_start上的数据框:

    pd.merge(df.drop('amount', axis=1), grouped_sum, on='week_start').drop('week_start', axis=1)
    

    结果:

      group       date  amount
    0     A 2018-01-01      10
    1     A 2018-01-14      40
    2     A 2018-01-15      40
    3     B 2018-02-03      30
    4     B 2018-02-04      30
    5     B 2018-02-05      30
    

    【讨论】:

    • 感谢您的解决方案。然而,这是倒数。 7天病房呢?
    • @addicted 请解释一下你的意思。
    猜你喜欢
    • 1970-01-01
    • 2021-08-14
    • 1970-01-01
    • 1970-01-01
    • 2018-11-14
    • 1970-01-01
    • 1970-01-01
    • 2018-03-13
    • 1970-01-01
    相关资源
    最近更新 更多