在groupby数据框(Python)中查找给定日期的最近日期

在groupby数据框(Python)中查找给定日期的最近日期,python,datetime,group-by,Python,Datetime,Group By,我试图在pandas数据框中生成上次付款日期字段,并且需要为每个客户(即groupby)找到给定的订单日期之前最近的付款日期 付款日期总是发生在订单日期之后,但可能需要不同的时间段,这很难使用排序和移位来查找最近的日期 这似乎是一种可行的方法,但我还没有找到一种方法来使用它 感谢所有能给我的帮助 Cust_No Order_Date Payment_Date Last_Payment_Date A 5/8/2014 6/8/2014

我试图在pandas数据框中生成
上次付款日期
字段,并且需要为每个客户(即groupby)找到给定的
订单日期
之前最近的
付款日期

付款日期
总是发生在
订单日期
之后,但可能需要不同的时间段,这很难使用排序和移位来查找最近的日期

这似乎是一种可行的方法,但我还没有找到一种方法来使用它

感谢所有能给我的帮助

Cust_No  Order_Date  Payment_Date  Last_Payment_Date
      A    5/8/2014      6/8/2014                Nat
      B    6/8/2014      1/5/2015                Nat
      B    7/8/2014      7/8/2014                Nat
      A    8/8/2014      1/5/2015           6/8/2014
      A    9/8/2014     10/8/2014           6/8/2014
      A  10/11/2014    12/11/2014          10/8/2014
      B  11/12/2014      1/1/2015           7/8/2014
      B    1/2/2015      2/2/2015           1/1/2015
      A    2/5/2015      5/5/2015           1/5/2015
      B    3/5/2015      4/5/2015           2/2/2015
基本上就是你想要的——它 可用于查找
Order\u Date
s在
Payment\u Date
s中的位置。在里面 特别是,它返回与每个 需要插入
订单日期
,以保留
付款日期
分类。例如,假设

In [266]: df['Payment_Date']
Out[266]: 
0   2014-06-08
2   2014-07-08
4   2014-10-08
5   2014-12-11
6   2015-01-01
1   2015-01-05
3   2015-01-05
7   2015-02-02
9   2015-04-05
8   2015-05-05
Name: Payment_Date, dtype: datetime64[ns]

In [267]: df['Order_Date']
Out[267]: 
0   2014-05-08
2   2014-07-08
4   2014-09-08
5   2014-10-11
6   2014-11-12
1   2014-06-08
3   2014-08-08
7   2015-01-02
9   2015-03-05
8   2015-02-05
Name: Order_Date, dtype: datetime64[ns]
然后
searchsorted
返回

In [268]: df['Payment_Date'].searchsorted(df['Order_Date'])
Out[268]: array([0, 1, 2, 3, 3, 0, 2, 5, 8, 8])
例如,第一个值0表示订单日期,
2014-05-08
, 必须在序号索引0处插入(在付款日期之前
2014-06-08
)以保持付款日期的排序。第二个值,1, 指示必须在以下位置插入订单日期,
2014-07-08
顺序索引1(在付款日期之后和之前) 保持付款日期的排序。其他指数也是如此

当然,现在有一些复杂情况:

  • 付款日期
    需要按排序顺序进行排序,以便
    搜索排序
    返回 有意义的结果:

    df = df.sort_values(by=['Payment_Date'])    
    
  • 我们需要按客户编号进行分组

    grouped = df.groupby('Cust_No')
    
  • 我们要的是付款日期之前的
    索引
    
    订单日期
    。因此,我们确实需要将指数减少1:

    idx = grp['Payment_Date'].searchsorted(grp['Order_Date']) 
    result = grp['Payment_Date'].iloc[idx-1]
    
  • 因此,
    grp['Payment\u Date'].iloc[idx-1]
    将获取先前的
    Payment\u Date

  • searchsorted
    返回0时,
    Order\u Date
    小于all
    付款日期
    s。在这种情况下我们需要NaT

    result[idx == 0] = pd.NaT
    

  • 所以把这一切放在一起

    import pandas as pd
    NaT = pd.NaT
    T = pd.Timestamp
    df = pd.DataFrame({
        'Cust_No': ['A', 'B', 'B', 'A', 'A', 'A', 'B', 'B', 'A', 'B'],
        'expected': [
            NaT,  NaT,  NaT, T('2014-06-08'), T('2014-06-08'), T('2014-10-08'), 
            T('2014-07-08'), T('2015-01-01'), T('2015-01-05'), T('2015-02-02')], 
        'Order_Date': [
            T('2014-05-08'), T('2014-06-08'), T('2014-07-08'), T('2014-08-08'), 
            T('2014-09-08'), T('2014-10-11'), T('2014-11-12'), T('2015-01-02'), 
            T('2015-02-05'), T('2015-03-05')], 
        'Payment_Date': [
            T('2014-06-08'), T('2015-01-05'), T('2014-07-08'), T('2015-01-05'), 
            T('2014-10-08'), T('2014-12-11'), T('2015-01-01'), T('2015-02-02'), 
            T('2015-05-05'), T('2015-04-05')]})
    
    def last_payment_date(s, df):
        grp = df.loc[s.index]
        idx = grp['Payment_Date'].searchsorted(grp['Order_Date']) 
        result = grp['Payment_Date'].iloc[idx-1]
        result[idx == 0] = pd.NaT
        return result
    
    df = df.sort_values(by=['Payment_Date'])    
    grouped = df.groupby('Cust_No')
    df['Last_Payment_Date'] = grouped['Payment_Date'].transform(last_payment_date, df)
    
    print(df)
    
    屈服

      Cust_No Order_Date Payment_Date   expected Last_Payment_Date
    0       A 2014-05-08   2014-06-08        NaT               NaT
    2       B 2014-07-08   2014-07-08        NaT               NaT
    4       A 2014-09-08   2014-10-08 2014-06-08        2014-06-08
    5       A 2014-10-11   2014-12-11 2014-10-08        2014-10-08
    6       B 2014-11-12   2015-01-01 2014-07-08        2014-07-08
    1       B 2014-06-08   2015-01-05        NaT               NaT
    3       A 2014-08-08   2015-01-05 2014-06-08        2014-06-08
    7       B 2015-01-02   2015-02-02 2015-01-01        2015-01-01
    9       B 2015-03-05   2015-04-05 2015-02-02        2015-02-02
    8       A 2015-02-05   2015-05-05 2015-01-05        2015-01-05
    

    付款日期
    是否总是在下一个
    订单日期
    之前?否,如客户B的前两个记录所示。如果找不到以前的付款日期,则应反映Nat。谢谢在尝试回答我自己的问题时,您能否再次检查您为
    上次付款日期提供的列是否100%正确?有些日期不匹配(2015年2月5日vs 2015年2月2日),我想确保我会给你你想要的。我对拼写错误感到非常抱歉!我已经改正了。