繁体   English   中英

Pandas:即使日期已经在月末,也能正确获取业务月末日期

[英]Pandas: Get Business Month-End Dates Correctly Even for Dates Already on Month-End

假设我有 dataframe 如下

date,ent_id,val
2021-03-23,101,61
2021-03-12,103,64
2021-03-15,101,32
2021-04-01,103,39
2021-04-02,101,71
2021-04-02,103,79
2021-04-30,101,51
2021-04-30,103,53
2021-05-31,101,28
2021-05-31,103,26
2021-05-31,101,47
2021-05-31,103,61
2021-06-06,101,45
2021-06-06,103,78
2021-06-07,101,23
2021-06-07,103,31
2021-07-31,101,14
2021-07-31,103,02
2021-07-31,101,82
2021-07-31,103,15

我想在 dataframe 中创建一个附加列,其中包含基于以下条件的月底日期

case 
when DAYNAME('date')='Sunday' then days_add(date,-2)
when DAYNAME('date')='Saturday' then days_add(date,-1)
else date 

所以 output 会是这样的

date,ent_id,val,month_end
2021-03-23,101,61,2021-03-31
2021-03-12,103,64,2021-03-31
2021-03-15,101,32,2021-03-31
2021-04-01,103,39,2021-04-30
2021-04-02,101,71,2021-04-30
2021-04-02,103,79,2021-04-30
2021-04-30,101,51,2021-04-30
2021-04-30,103,53,2021-04-30
2021-05-31,101,28,2021-05-31
2021-05-31,103,26,2021-05-31
2021-05-31,101,47,2021-05-31
2021-05-31,103,61,2021-05-31
2021-06-06,101,45,2021-06-30
2021-06-06,103,78,2021-06-30
2021-06-07,101,23,2021-06-30
2021-06-07,103,31,2021-06-30
2021-07-31,101,14,2021-07-31
2021-07-31,103,02,2021-07-31
2021-07-31,101,82,2021-07-31
2021-07-31,103,15,2021-07-31

我的努力

import pandas as pd
from datetime import timedelta
from pandas.tseries.offsets import MonthEnd
import numpy as np

df.loc[(df['date']+MonthEnd(0)).dt.day_name()=='Sunday','month_end'] =[df.loc[(df['date']+MonthEnd(0)).dt.day_name()=='Sunday']['date']+timedelta(days=-2)]
df.loc[(df['date']+MonthEnd(0)).dt.day_name()=='Saturday','month_end'] =[df.loc[(df['date']+MonthEnd(0)).dt.day_name()=='Saturday']['date']+timedelta(days=-1)]

但收到此错误

ValueError: Must have equal len keys and value when setting with an ndarray

任何其他更好的解决方案都是最受欢迎的

这应该有效:

df['month_end'] = df.date + pd.offsets.MonthEnd(n=0)
df.loc[df.index.day_name()=='Sunday', 'month_end'] -= pd.DateOffset(days=2)
df.loc[df.index.day_name()=='Saturday', 'month_end'] -= pd.DateOffset(days=1)

请注意,如果您对当月的最后一个工作日感兴趣,您可以简单地执行以下操作:

df['month_end'] = df.date + pd.offsets.BusinessMonthEnd(n=0)

您可以使用pd.offsets.MonthEnd(n=0)然后针对周日和周六进行调整。 请注意,需要n=0 ,否则 2021-07-31 将前滚到 2021-08-31。

df['month_end'] = df['date'] + pd.offsets.MonthEnd(n=0)
df.loc[df['month_end'].dt.day_name() == 'Sunday', 'month_end'] -= pd.DateOffset(2)
df.loc[df['month_end'].dt.day_name() == 'Saturday', 'month_end'] -= pd.DateOffset(1)


print(df)

         date  ent_id  val  month_end
0  2021-03-23     101   61 2021-03-31
1  2021-03-12     103   64 2021-03-31
2  2021-03-15     101   32 2021-03-31
3  2021-04-01     103   39 2021-04-30
4  2021-04-02     101   71 2021-04-30
5  2021-04-02     103   79 2021-04-30
6  2021-04-30     101   51 2021-04-30
7  2021-04-30     103   53 2021-04-30
8  2021-05-31     101   28 2021-05-31
9  2021-05-31     103   26 2021-05-31
10 2021-05-31     101   47 2021-05-31
11 2021-05-31     103   61 2021-05-31
12 2021-06-06     101   45 2021-06-30
13 2021-06-06     103   78 2021-06-30
14 2021-06-07     101   23 2021-06-30
15 2021-06-07     103   31 2021-06-30
16 2021-07-31     101   14 2021-07-30
17 2021-07-31     103    2 2021-07-30
18 2021-07-31     101   82 2021-07-30
19 2021-07-31     103   15 2021-07-30

请注意,尽管您似乎希望获得一个月的最后一个营业日期,但我们不能简单地使用pd.offsets.BMonthEnd(n=0) ,因为 2021-07-31 仍将前滚到 2021-08-31。

编辑:使用 BMonthEnd 的解决方案

当我第一次看到这个问题时,我立刻想到的是,也许我们可以利用pd.offsets.BMonthEnd来解决这个问题。

我也知道对于pd.offsets.MonthEnd ,我们可以使用参数n=0 (或简单地0 )来确保在锚点上的日期不会滚动(如果日期已经在月末,则在锚点上)在这种情况下是日期)。 因此,我最初的尝试是使用pd.offsets.BMonthEnd(n=0) 令我惊讶的是,它的行为与 MonthEnd 对应物的行为不同。 日期2021-07-31仍前滚至2021-08-31

由于这种问题非常普遍,我想提供一个解决方法,让我们仍然可以使用BMonthEnd ,而不是提供代码来检查和修改周日和周六。

这是使BMonthEnd的行为类似于MonthEnd(n=0)的解决方法代码:

df['business_month_end'] = df['date'] + pd.offsets.MonthEnd(0) - pd.offsets.MonthBegin() + pd.offsets.BMonthEnd()

这里, MonthEnd(0)MonthEnd(n=0)相同,而MonthEnd()BMonthEnd()不传递参数与传递n=1相同(默认)。

机制是我们借用MonthEnd(n=0)的特性,即使在锚点上也保持锚点,并获取该日期的月初(应该是同一个月内的第一个日期),然后将BMonthEnd function 应用于让它为我们提供同月的最后一个营业日期(如果日期在星期日和星期六,则进行调整)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM