Python 基于滚动周期的上一行的最大值

Python 基于滚动周期的上一行的最大值,python,pandas,rolling-computation,Python,Pandas,Rolling Computation,我的数据集如下: data = pd.DataFrame({ 'ID': ['27459', '27459', '27459', '27459', '27459', '27459', '27459', '48002', '48002', '48002'], 'Invoice_Date': ['2020-06-26', '2020-06-29', '2020-06-30', '2020-07-14', '2020-07-25',

我的数据集如下:


data = pd.DataFrame({
        'ID':  ['27459', '27459', '27459', '27459', '27459', '27459', '27459', '48002', '48002', '48002'],
        'Invoice_Date': ['2020-06-26', '2020-06-29', '2020-06-30', '2020-07-14', '2020-07-25', 
                         '2020-07-30', '2020-08-02', '2020-05-13', '2020-06-20', '2020-06-28'],
        'Payment_Term': [7,8,3,6,4,7,8,5,3,6],
        'Payment_Date': ['2020-07-05', '2020-07-05','2020-07-03', '2020-07-21', '2020-07-31', 
                         '2020-08-15', '2020-08-22', '2020-06-16', '2020-06-23', '2020-07-05'],
        'Due_Date': ['2020-07-03', '2020-07-07', '2020-07-03', '2020-07-20', '2020-07-29', 
                         '2020-08-06', '2020-08-10', '2020-05-18', '2020-06-23', '2020-07-04'],
        'Delay': [2,-2,0,1,2,9,12,29,0,1],
        'Difference_Date': [0,3,1,14,11,5,3,0,38,8],
        })
data
我需要添加另一列
Max
,该列显示上一行
Delay
的最大值。它将有另一个条件,即,它应该是一个30天的滚动期。这意味着,对于当前行中的
Max
,将采用前一行中的最大延迟,即从当前行
发票日期起30天内的延迟

所需的输出为:

ID     Invoice_Date Payment_Term  Payment_Date       Due_Date  Delay    Difference_Date           Max

27459    2020-06-26            7    2020-07-05     2020-07-03      2                  0             0
27459    2020-06-29            8    2020-07-05     2020-07-07     -2                  3             2
27459    2020-06-30            3    2020-07-03     2020-07-03      0                  1             2
27459    2020-07-14            6    2020-07-21     2020-07-20      1                  14            2  
27459    2020-07-25            4    2020-07-31     2020-07-29      2                  11            2
27459    2020-07-30            7    2020-08-15     2020-08-06      9                  5             2
27459    2020-08-02            8    2020-08-22     2020-08-10      12                 3             9
48002    2020-05-13            5    2020-06-16     2020-05-18      29                 0             0
48002    2020-06-20            3    2020-06-23     2020-06-23      0                  38           29
48002    2020-06-28            6    2020-07-05     2020-07-04      1                  8            29

一种可能的方法是:

data['Invoice_Date'] = pd.to_datetime(data['Invoice_Date'])
groups = data.groupby('ID')

for group_name, df_group in groups:
    for idx,row in df_group.iterrows():
        dt_range = pd.date_range(row['Invoice_Date'] - pd.to_timedelta(30, 'day'), row['Invoice_Date'])[:-1]
        data.loc[idx, 'max'] = df_group[df_group.Invoice_Date.isin(dt_range)].Delay.max()

print(data)
输出:

      ID Invoice_Date  Payment_Term Payment_Date    Due_Date  Delay    Difference_Date  max  
0  27459   2020-06-26             7   2020-07-05  2020-07-03      2                  0  NaN  
1  27459   2020-06-29             8   2020-07-05  2020-07-07     -2                  3  2.0  
2  27459   2020-06-30             3   2020-07-03  2020-07-03      0                  1  2.0  
3  27459   2020-07-14             6   2020-07-21  2020-07-20      1                 14  2.0  
4  27459   2020-07-25             4   2020-07-31  2020-07-29      2                 11  2.0  
5  27459   2020-07-30             7   2020-08-15  2020-08-06      9                  5  2.0  
6  27459   2020-08-02             8   2020-08-22  2020-08-10     12                  3  9.0  
7  48002   2020-05-13             5   2020-06-16  2020-05-18     29                  0  NaN  
8  48002   2020-06-20             3   2020-06-23  2020-06-23      0                 38  NaN  
9  48002   2020-06-28             6   2020-07-05  2020-07-04      1                  8  0.0

您可以使用
数据填充NAN。fillna(0)
。请查看ID“48002”的第一个值是否为NaN,因为之前的值不在30天范围内。

一种可能的方法:

data['Invoice_Date'] = pd.to_datetime(data['Invoice_Date'])
groups = data.groupby('ID')

for group_name, df_group in groups:
    for idx,row in df_group.iterrows():
        dt_range = pd.date_range(row['Invoice_Date'] - pd.to_timedelta(30, 'day'), row['Invoice_Date'])[:-1]
        data.loc[idx, 'max'] = df_group[df_group.Invoice_Date.isin(dt_range)].Delay.max()

print(data)
输出:

      ID Invoice_Date  Payment_Term Payment_Date    Due_Date  Delay    Difference_Date  max  
0  27459   2020-06-26             7   2020-07-05  2020-07-03      2                  0  NaN  
1  27459   2020-06-29             8   2020-07-05  2020-07-07     -2                  3  2.0  
2  27459   2020-06-30             3   2020-07-03  2020-07-03      0                  1  2.0  
3  27459   2020-07-14             6   2020-07-21  2020-07-20      1                 14  2.0  
4  27459   2020-07-25             4   2020-07-31  2020-07-29      2                 11  2.0  
5  27459   2020-07-30             7   2020-08-15  2020-08-06      9                  5  2.0  
6  27459   2020-08-02             8   2020-08-22  2020-08-10     12                  3  9.0  
7  48002   2020-05-13             5   2020-06-16  2020-05-18     29                  0  NaN  
8  48002   2020-06-20             3   2020-06-23  2020-06-23      0                 38  NaN  
9  48002   2020-06-28             6   2020-07-05  2020-07-04      1                  8  0.0

您可以使用
数据填充NAN。fillna(0)
。请查看ID“48002”的第一个值是否为NaN,因为之前的值不在30天范围内。

您可以使用
滚动
方法仅对一些过去的元素进行操作。但是,日期应该是单调的(升序或降序),这意味着应该对日期进行排序

您可以尝试以下操作:

df['Invoice_Date'] = pd.to_datetime(df['Invoice_Date'])
df.set_index('Invoice_Date', inplace=True)
df.sort_index(inplace=True)

df['max'] = df.groupby('ID')['Delay'].transform(lambda x: x.rolling('30D', closed='left').max())
编辑:根据@Cainã的建议,包含了一个
groupby
,以保证对每个唯一的
ID

需要使用
closed
参数指定不应包括当天

新数据框如下所示(此处仅按
Invoice\u Date
排序)

如果我们也按
ID
对其进行排序(通过运行
df.reset_index().sort_值(['ID','Invoice_Date'))
),我们会得到:


您可以使用
rolling
方法仅对一些过去的元素进行操作。但是,日期应该是单调的(升序或降序),这意味着应该对日期进行排序

您可以尝试以下操作:

df['Invoice_Date'] = pd.to_datetime(df['Invoice_Date'])
df.set_index('Invoice_Date', inplace=True)
df.sort_index(inplace=True)

df['max'] = df.groupby('ID')['Delay'].transform(lambda x: x.rolling('30D', closed='left').max())
编辑:根据@Cainã的建议,包含了一个
groupby
,以保证对每个唯一的
ID

需要使用
closed
参数指定不应包括当天

新数据框如下所示(此处仅按
Invoice\u Date
排序)

如果我们也按
ID
对其进行排序(通过运行
df.reset_index().sort_值(['ID','Invoice_Date'))
),我们会得到:


df.滚动
可以完成工作,而且可能是最有效的

df["Invoice_Date"] = df.Invoice_Date.astype("datetime64")    
df["Max"] = df.groupby("ID").rolling("30d", on="Invoice_Date", closed="left").Delay.max().values
结果:

      ID Invoice_Date  Payment_Term Payment_Date    Due_Date  Delay  Difference_Date  Max
0  27459   2020-06-26             7   2020-07-05  2020-07-03      2                0  NaN
1  27459   2020-06-29             8   2020-07-05  2020-07-07     -2                3  2.0
2  27459   2020-06-30             3   2020-07-03  2020-07-03      0                1  2.0
3  27459   2020-07-14             6   2020-07-21  2020-07-20      1               14  2.0
4  27459   2020-07-25             4   2020-07-31  2020-07-29      2               11  2.0
5  27459   2020-07-30             7   2020-08-15  2020-08-06      9                5  2.0
6  27459   2020-08-02             8   2020-08-22  2020-08-10     12                3  9.0
7  48002   2020-05-13             5   2020-06-16  2020-05-18     29                0  NaN
8  48002   2020-06-20             3   2020-06-23  2020-06-23      0               38  NaN
9  48002   2020-06-28             6   2020-07-05  2020-07-04      1                8  0.0

df.滚动
可以完成工作,而且可能是最有效的

df["Invoice_Date"] = df.Invoice_Date.astype("datetime64")    
df["Max"] = df.groupby("ID").rolling("30d", on="Invoice_Date", closed="left").Delay.max().values
结果:

      ID Invoice_Date  Payment_Term Payment_Date    Due_Date  Delay  Difference_Date  Max
0  27459   2020-06-26             7   2020-07-05  2020-07-03      2                0  NaN
1  27459   2020-06-29             8   2020-07-05  2020-07-07     -2                3  2.0
2  27459   2020-06-30             3   2020-07-03  2020-07-03      0                1  2.0
3  27459   2020-07-14             6   2020-07-21  2020-07-20      1               14  2.0
4  27459   2020-07-25             4   2020-07-31  2020-07-29      2               11  2.0
5  27459   2020-07-30             7   2020-08-15  2020-08-06      9                5  2.0
6  27459   2020-08-02             8   2020-08-22  2020-08-10     12                3  9.0
7  48002   2020-05-13             5   2020-06-16  2020-05-18     29                0  NaN
8  48002   2020-06-20             3   2020-06-23  2020-06-23      0               38  NaN
9  48002   2020-06-28             6   2020-07-05  2020-07-04      1                8  0.0


这不是按发票日期订购发票日期是根据IDi订购的请参见。是否也要按id对其进行分组?是的,需要按IDi对其进行分组。看起来
Max
的最后一个元素有误:29不在30天窗口内。这不是按发票日期排序。发票日期是根据IDi排序的。请参阅。你也要按id分组吗?是的,它需要按id分组。看起来
Max
的最后一个元素是错误的:29不在30天窗口内。我认为这不符合要求-他想要30天,不包括当前行。对不起,你是对的,我错过了。我已经改正了,雷卢布鲁斯托!它避免了不必要的
循环
+1。尽管它仍然不符合OP的要求。考虑编辑你的答案,包括一个<代码> GlpBy< /Cl>语句。例如,“代码”> DF['Max '] = DF.GROMPBY(“ID”)[ [延迟] ]。转换(lambda x:x.滚动(‘30d’,‘关闭’=左’))/<代码>加上代码> df.ReStIdIdx()。但在这里它的方式更快!伟大的建议@CainãMaxCouto Silva!我很难包含一个
groupby('ID')
,但这确实有效!我认为这不符合要求-他想要30天,不包括目前的赛道对不起,你是对的,我错过了。我已经改正了,雷卢布鲁斯托!它避免了不必要的
循环
+1。尽管它仍然不符合OP的要求。考虑编辑你的答案,包括一个<代码> GlpBy< /Cl>语句。例如,“代码”> DF['Max '] = DF.GROMPBY(“ID”)[ [延迟] ]。转换(lambda x:x.滚动(‘30d’,‘关闭’=左’))/<代码>加上代码> df.ReStIdIdx()。但在这里它的方式更快!伟大的建议@CainãMaxCouto Silva!我很难包含一个
groupby('ID')
,但这确实有效!用两行话来概括一切是相当优雅的。但这给我带来了一个错误(与相同)。你用的是什么版本的熊猫?
pd.\uuuuuu版本\uuuuuuuuu->1.1.4tanks@Ralubrusto:)我其实觉得它有点不可读。不过可能表现得很好!我使用的是
1.0.5
。升级到最新版本使其工作完美。干得好!:)回答得很好。我仍然不确定在使用
groupby
.rolling()
是如何工作的(关于数据顺序),但我添加了一个额外的行,其中27459作为ID,这似乎把结果搞砸了。因此,我建议在应用前对组日期进行排序(例如,
df=df.sort_值(['ID','Invoice_Date'])
)。无论如何,干得好!用两行话来概括一切是相当优雅的。但这给我带来了一个错误(与相同)。你用的是什么版本的熊猫?
pd.\uuuuuu版本\uuuuuuuuu->1.1.4tanks@Ralubrusto:)我其实觉得它有点不可读。不过可能表现得很好!我使用的是
1.0.5
。升级到最新版本使其工作完美。干得好!:)回答得很好。我仍然不确定在使用
groupby
.rolling()
是如何工作的(关于数据顺序),但我添加了一个额外的行,其中27459作为ID,这似乎把结果搞砸了。所以我会