使用np.busday_count遇ValueError:holidays需为一维数组的问题
问题:计算自定义节假日工作日时触发维度错误
背景
我有一个用Python holidays库生成的DataFrame,包含月末日期(PredictionTargetDateEOM)、月初日期(PredictionTargetDateBOM)、次月首日(DayAfterTargetDateEOM)及月度工作日数字段,示例如下:
PredictionTargetDateEOM PredictionTargetDateBOM DayAfterTargetDateEOM business_days 0 2018-12-31 2018-12-01 2019-01-01 20 1 2019-01-31 2019-01-01 2019-02-01 21 2 2019-02-28 2019-02-01 2019-03-01 20 3 2018-11-30 2018-11-01 2018-12-01 21 4 2018-10-31 2018-10-01 2018-11-01 23 ... ... ... ... ... 172422 2020-10-31 2020-10-01 2020-11-01 22 172423 2020-11-30 2020-11-01 2020-12-01 20 172424 2020-12-31 2020-12-01 2021-01-01 22 172425 2020-09-30 2020-09-01 2020-10-01 21 172426 2020-08-31 2020-08-01 2020-09-01 21
生成该DataFrame的代码如下:
predicted_df['PredictionTargetDateBOM'] = predicted_df.apply(lambda x: pd.to_datetime(x['PredictionTargetDateEOM']).replace(day=1), axis = 1) #Get first day of the target month predicted_df['PredictionTargetDateEOM'] = pd.to_datetime(predicted_df['PredictionTargetDateEOM']) predicted_df['DayAfterTargetDateEOM'] = predicted_df['PredictionTargetDateEOM'] + timedelta(days=1) #Get the first day of the month after target month. i.e. M+2 predicted_df['business_days'] = predicted_df.apply(lambda x: np.busday_count(x['PredictionTargetDateBOM'].date(), x['DayAfterTargetDateEOM'].date(), holidays=[list(holidays.US(years=x['PredictionTargetDateBOM'].year).keys())[index] for index in [list(holidays.US(years=x['PredictionTargetDateBOM'].year).values()).index(item) for item in rocket_holiday_including_observed if item in list(holidays.US(years=x['PredictionTargetDateBOM'].year).values())]] ), axis = 1) #Count number of business days of the target month
需求与报错
我想要添加business_days_rocket列,代码如下:
predicted_df['business_days_rocket'] = predicted_df.apply(lambda x: np.busday_count(x['PredictionTargetDateBOM'].date(), x['DayAfterTargetDateEOM'].date(), holidays=[list({k: v for k, v in holidays.US(years=x['PredictionTargetDateBOM'].year).items() if v in my_set})]), axis = 1)
其中my_set定义为:
my_list = [ "New Year's Day", "Martin Luther King Jr. Day", "Memorial Day", "Independence Day", "Labor Day", "Thanksgiving", "Christmas Day", "New Year's Day (Observed)", "Martin Luther King Jr. Day (Observed)", "Memorial Day (Observed)", "Independence Day (Observed)", "Labor Day (Observed)", "Thanksgiving (Observed)", "Christmas Day (Observed)", ] my_set = set(my_list)
运行后触发错误:
ValueError: holidays must be a provided as a one-dimensional array
我无法理解该错误,因为list({k: v for k, v in holidays.US(years=x['PredictionTargetDateBOM'].year).items() if v in my_set})的输出是一维日期列表:
[datetime.date(2022, 1, 1), datetime.date(2022, 1, 17), datetime.date(2022, 5, 30), datetime.date(2022, 7, 4), datetime.date(2022, 9, 5), datetime.date(2022, 11, 24), datetime.date(2022, 12, 25), datetime.date(2022, 12, 26)]
这个格式和之前可用的代码输出格式一致,请问该如何解决?
解决方案
错误原因
你在代码里给holidays参数传的是[list({...})],相当于把筛选得到的一维日期列表额外包裹了一层方括号,最终传给np.busday_count的是一个二维数组(比如[[2022-01-01, 2022-01-17,...]]),这违反了参数要求,因此触发维度错误。
之前的旧代码虽然也有[list(...)[index]...]的写法,但那是列表推导式,最终生成的是一维列表,和你当前的错误写法结构完全不同。
修正代码
写法一:去掉外层多余的方括号
直接将筛选后的日期列表传给holidays参数:
predicted_df['business_days_rocket'] = predicted_df.apply( lambda x: np.busday_count( x['PredictionTargetDateBOM'].date(), x['DayAfterTargetDateEOM'].date(), holidays=list({k: v for k, v in holidays.US(years=x['PredictionTargetDateBOM'].year).items() if v in my_set}) ), axis=1 )
写法二:更直观的筛选方式
不需要转字典,直接遍历holidays.US()的键值对筛选,代码可读性更高:
predicted_df['business_days_rocket'] = predicted_df.apply( lambda x: np.busday_count( x['PredictionTargetDateBOM'].date(), x['DayAfterTargetDateEOM'].date(), holidays=[date for date, name in holidays.US(years=x['PredictionTargetDateBOM'].year).items() if name in my_set] ), axis=1 )
内容的提问来源于stack exchange,提问作者Hefe
相关产品推荐
相关产品推荐

