【问题标题】:Compute days-until-next-event based on date diffs in dataframe根据数据框中的日期差异计算直到下一个事件的天数
【发布时间】:2018-02-06 21:36:26
【问题描述】:

我有一个 pandas 数据框,我想计算 days_until_next_event 用于:

df = pd.DataFrame({'message_count': [1, 3, 5, 6, 2, 8, 10, 2], 'event_date': ['2016-01-05', '2016-01-05', '2016-01-05', '2016-01-13', '2016-01-13', '2016-01-13', '2016-01-28', '2016-01-28'], 'message_date': ['2016-01-05', '2016-01-06', '2016-01-10', '2016-01-13', '2016-01-16', '2016-01-22', '2016-01-28', '2016-01-30']})

event_date  message_count   message_date
2016-01-05       1           2016-01-05
2016-01-05       3           2016-01-06
2016-01-05       5           2016-01-10
2016-01-13       6           2016-01-13
2016-01-13       2           2016-01-16
2016-01-13       8           2016-01-22
2016-01-28       10          2016-01-28
2016-01-28       2           2016-01-30

预期的数据框如下所示:

days_until_next_event   event_date  message_count   message_date    
      0 days            2016-01-05       1           2016-01-05 
      7 days            2016-01-05       3           2016-01-06 
      3 days            2016-01-05       5           2016-01-10 
      0 days            2016-01-13       6           2016-01-13 
      12 days           2016-01-13       2           2016-01-16 
      6 days            2016-01-13       8           2016-01-22 
      0 days            2016-01-28      10           2016-01-28 
      NaT               2016-01-28       2           2016-01-30 

其中days_until_next_eventmessage_date 和下一个 event_date 之间的区别。如果两个日期相同,则其值为 0。我可以通过以下方式获取自上次事件以来的天数:

df2['days_since_last_dte'] = [(message - event) for message, event in zip(df2['message_date'], df2['event_date'])]

但在添加最后一个与下一个“新”event_date进行比较时遇到问题@

【问题讨论】:

  • 请解释一下dune = "7 days" 是如何记录event_date=2016-01-05, message_count=3, message_date=2016-01-06 的?为什么下一个新的 message_date 不是 2016-01-10(从第 3 行开始),因此是“5 天”?
  • @smci 因为沙丘是根据下一个 new event_date 而不是 event_date 本身计算的。在这种情况下,对于event_date=2016-01-05, message_count=3, message_date=2016-01-06,它将是2016-01-13 - 2016-01-06 = 7 天。对于message_date = 2016-01-10,它将是2016-13-01 - 2016-01-10 = 3 天。所有message_datesevent_date = 2016-01-05 都将在沙丘计算中使用event_date = 2016-01-13,因为这是下一个事件。希望这能澄清你的问题。

标签: python-3.x pandas datetime


【解决方案1】:

IIUC(PS:假设你的df是排序的,如果不是sort_values首先)

df['New']=df.event_date.map(pd.Series(df.event_date.unique()[1:],index=df.event_date.unique()[:-1]))

df.loc[df.groupby('event_date').head(1).index,'DiffDays']=0

df
Out[1191]: 
   event_date  message_count message_date        New          DiffDays
0  2016-01-05              1   2016-01-05 2016-01-13                 0
1  2016-01-05              3   2016-01-06 2016-01-13   7 days 00:00:00
2  2016-01-05              5   2016-01-10 2016-01-13   3 days 00:00:00
3  2016-01-13              6   2016-01-13 2016-01-28                 0
4  2016-01-13              2   2016-01-16 2016-01-28  12 days 00:00:00
5  2016-01-13              8   2016-01-22 2016-01-28   6 days 00:00:00
6  2016-01-28             10   2016-01-28        NaT                 0
7  2016-01-28              2   2016-01-30        NaT               NaT

【讨论】:

    【解决方案2】:

    使用bfill:

    df.event_date = pd.to_datetime(df.event_date)
    df.message_date = pd.to_datetime(df.message_date)
    

    创建一个新列'next_event_date'

    df['next_event_date'] = df.loc[df.event_date != df.event_date.shift(1),'event_date']
    

    将 next_event_date 回填到阵容数据:

    df['next_event_date'] = df['next_event_date'].bfill()
    

    减去 next_event_date 和 message_date:

    df['days_until_next_event'] = df['next_event_date'] - df['message_date']
    print(df)
    

    输出:

      event_date  message_count message_date next_event_date days_until_next_event
    0 2016-01-05              1   2016-01-05      2016-01-05                0 days
    1 2016-01-05              3   2016-01-06      2016-01-13                7 days
    2 2016-01-05              5   2016-01-10      2016-01-13                3 days
    3 2016-01-13              6   2016-01-13      2016-01-13                0 days
    4 2016-01-13              2   2016-01-16      2016-01-28               12 days
    5 2016-01-13              8   2016-01-22      2016-01-28                6 days
    6 2016-01-28             10   2016-01-28      2016-01-28                0 days
    7 2016-01-28              2   2016-01-30             NaT                   NaT
    

    【讨论】:

    • 这太好了,谢谢!我将.bfill() 用于其他用途,并没有考虑将它与.shift() 一起用于此目的!
    猜你喜欢
    • 2021-10-06
    • 2019-08-24
    • 2021-05-28
    • 1970-01-01
    • 1970-01-01
    • 2021-12-31
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多