Pandas - 对于一列中的给定日期,另一列中的日期少于该日期?

时间:2018-01-19 05:39:57

标签: python pandas date numpy dataframe

我有下表:

id | invoice_date | payment_date
--------------------------------
1  | 2017-03-01   | 2017-03-03
1  | 2017-03-04   | 2017-03-06
1  | 2017-03-04   | 2017-03-11
1  | 2017-03-15   | 2017-03-16
1  | 2017-03-21   | 2017-03-31
2  | 2017-01-22   | 2017-01-22
2  | 2017-01-24   | 2017-01-25

我想知道:对于表中的任何给定索引,索引较少的付款日期少于索引的发票日期?也就是说,对于给定的发票日期,提前支付的付款日期是多少?理想情况下,我想为每个id(分组)执行此操作,因此我有类似的内容:

id | invoice_date | payment_date | num_pay_dates_less_than_inv_date
------------------------------------------------------------------
1  | 2017-03-01   | 2017-03-03   | 0
1  | 2017-03-04   | 2017-03-06   | 1
1  | 2017-03-04   | 2017-03-11   | 1
1  | 2017-03-15   | 2017-03-16   | 3
1  | 2017-03-21   | 2017-03-31   | 4
2  | 2017-01-22   | 2017-01-22   | 0
2  | 2017-01-24   | 2017-01-25   | 1

2 个答案:

答案 0 :(得分:2)

Numpy解决方案。使用广播比较,然后沿第一轴进行cumsum操作。最后,提取对角元素并分配给df

v = (df.invoice_date[:, None] > df.payment_date.values).cumsum(1)
df['num_pay_dates_less_than_inv_date'] = v[np.diag_indices_from(v)]

df

   id invoice_date payment_date  num_pay_dates_less_than_inv_date
0   1   2017-03-01   2017-03-03                                 0
1   1   2017-03-04   2017-03-06                                 1
2   1   2017-03-04   2017-03-11                                 1
3   1   2017-03-15   2017-03-16                                 3
4   1   2017-03-21   2017-03-31                                 4
5   2   2017-01-22   2017-01-22                                 0
6   2   2017-01-24   2017-01-25                                 1

这要求两列都采用日期时间格式(否则,比较是词典编纂,通常没问题,但这取决于您当时的日期格式)。

答案 1 :(得分:0)

我能够使用@COLDSPEEDs建议在他/她的回答中写一个循环。在大小为50K的数据帧上,循环实现比非循环实现快20倍。数据框的列是id,value1和value2。

def f(grp):

    dxv = {}
    for ix, val in zip(grp.index, grp.value1[:, None]):
        if (val > grp.value2.values[:ix]).any():
            dxv[ix] = (val > grp.value2.values[:ix]).cumsum()[-1]
        else:
            dxv[ix] = 0
    return pd.Series(dxv)

这适用于我的案例:

df['num_pay_dates_less_than_inv_date'] = \
df.groupby(['id']).apply(f).reset_index(drop=True)

随意进一步优化。