df1
JavaScript
x
6
1
no From To check
2
1 27-Jan-20 28-Mar-20 a
3
2 28-Mar-20 12-Apr-20 a
4
3 29-May-20 29-May-20 b
5
4 5-Apr-20 12-Apr-20 b
6
df2
JavaScript
1
4
1
col1 col2
2
a 9-Apr-20
3
b 30-Mar-20
4
df
JavaScript
1
6
1
no From To check total Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2
1 27-Jan-20 28-Mar-20 a 45 5 20 20
3
2 28-Mar-20 12-Apr-20 a 9 2 7
4
3 29-May-20 29-May-20 b 1 1
5
4 5-Apr-20 12-Apr-20 b 5 5
6
i need to calculate 2 things
- column “Total” based on working days between “From” and “To” and include any holiday from df2.
- split the “Total” column in respective months (Jan to Dec columns)
For part 1 : The column “total” in df1 is calculated using
JavaScript
1
2
1
np.busday_count('2020-01-27','2020-03-28')
2
but this is not acurate and not able to include holiday(df2)in this i tried to directly create dataframe using
JavaScript
1
3
1
df['total']=np.busday_count(df1['From'].astype('datetime64[D]')
2
,df1['To'].astype('datetime64[D]'))
3
but it is giving error.
Advertisement
Answer
You can use bdate_range
in a custom function
JavaScript
1
35
35
1
# dict of num to month mapping
2
months = pd.tseries.frequencies.MONTH_ALIASES
3
4
df2['col2'] = pd.to_datetime(df2['col2'], dayfirst=True)
5
6
# holiday month
7
df['holiday'] = df['check'].map(df2.set_index(['col1'])['col2']).dt.month
8
9
def count_by_month(s):
10
11
start, end, holiday = s['From'], s['To'], s['holiday']
12
13
valid_dates = pd.bdate_range(start=start, end=end).month
14
count = dict(pd.Series(valid_dates).value_counts())
15
16
# subtract holidays
17
if holiday in count:
18
count[holiday] -= 1
19
20
return pd.concat([s, pd.Series({v: count.get(k, 0) for k, v in months.items()})], axis=0)
21
22
print(df)
23
24
no From To check total holiday JAN FEB MAR APR
25
0 1 27-Jan-20 28-Mar-20 a 45 4 5 20 20 0
26
1 2 28-Mar-20 12-Apr-20 a 9 4 0 0 2 7
27
2 3 29-May-20 29-May-20 b 1 3 0 0 0 0
28
3 4 5-Apr-20 12-Apr-20 b 5 3 0 0 0 5
29
30
MAY JUN JUL AUG SEP OCT NOV DEC
31
0 0 0 0 0 0 0 0 0
32
1 0 0 0 0 0 0 0 0
33
2 1 0 0 0 0 0 0 0
34
3 0 0 0 0 0 0 0 0
35