My question is different than the following:
Question1: Week of a month pandas Quesiton2: Week number of the month
The above question deals with assuming 7 days in a week. It attempts to count the number of 7 days week there are. My data is composed of (business days) daily prices and there can be at times missing days of the week because the market was closed for holiday.
My question is how does one find the week of the month given a date. Note I highlighted "given a date" because this process is processed daily so any answers that looks ahead till the end of the month will likely not work.
My attempts has been the look ahead which isn't optimal:
def is_third_friday(s):
d = datetime.datetime.strptime(s, '%Y-%m-%d')
return d.weekday() == 5 and 15 <= d.day <= 21
dow = deepcopy(data['Close'] * np.nan).to_frame()
dow.columns = ['OpexFriday']
dow['next_date'] = pd.Series([str(i.date() + datetime.timedelta(days=1)) for i in dow.index]).values
dow['OpexFriday'] = pd.Series([is_third_friday(str(i)) for i in dow['next_date']]).values
dow['OpexWeek'] = (dow['OpexFriday'] * 1).replace(0, np.nan).fillna(method='bfill', limit=4).replace(np.nan, 0) == True
I don't know how to provide some sample data
but if you go to "https://aroussi.com/post/python-yahoo-finance" page and use the authors yfinance package, you will be able to get some price data to work with.
The functions above will find the 3rd week of the month (all True). In addition, it will set the Friday of that week too.
Let me know if you see any problem with the question or if its a duplicate. I have searched a while for a solution.
Method 1: using Python for-loops. Function new_case_count() takes in DataFrame object, iterates over it and converts indexes, which are dates in string format, to Pandas Datetime format. Based on the date's day of the week, each week's new cases count is calculated and stored in a list.
Pandas has a built-in function called to_datetime()that converts date and time in string format to a DateTime object. As you can see, the 'date' column in the DataFrame is currently of a string-type object. Thus, to_datetime() converts the column to a series of the appropriate datetime64 dtype.
One way could be to use timedelta
to change any date to the next Friday, then check if this following Friday is between 15 and 21.
from datetime import datetime, timedelta
def OpexWeek (s):
d = datetime.strptime(s, '%Y-%m-%d')
day = (d+timedelta(days=(4-d.weekday())%7)).day
return (day>=15) & (day<=21)
then you get
#for the example the second Friday of June 2020:
OpexWeek('2020-06-12')
False
# the Monday after is True because part of the OpexWeek
OpexWeek('2020-06-15')
True
Note: one thing to know is that the Saturday and the Sunday before the OpexWeek are True, but because you said your data is business days, then it should not matter.
The pandas version to use on Series of datetime could be:
def OpexWeekPd (ser):
return (ser+pd.to_timedelta((4-ser.dt.weekday)%7, unit='d')).dt.day.between(15,21)
With a small example:
print (
pd.DataFrame({'date':pd.bdate_range('2020-06-01', '2020-06-30').astype(str)})
.assign(isOpexWeek=lambda x: x['date'].apply(OpexWeek),
isIpexWeekPd=lambda x: OpexWeekPd(pd.to_datetime(x['date'])))
)
date isOpexWeek isIpexWeekPd
0 2020-06-01 False False
1 2020-06-02 False False
2 2020-06-03 False False
3 2020-06-04 False False
4 2020-06-05 False False
5 2020-06-08 False False
6 2020-06-09 False False
7 2020-06-10 False False
8 2020-06-11 False False
9 2020-06-12 False False
10 2020-06-15 True True
11 2020-06-16 True True
12 2020-06-17 True True
13 2020-06-18 True True
14 2020-06-19 True True
15 2020-06-22 False False
16 2020-06-23 False False
17 2020-06-24 False False
18 2020-06-25 False False
19 2020-06-26 False False
20 2020-06-29 False False
21 2020-06-30 False False
We can easily modify your function to work on the index:
# sample data
dow = pd.DataFrame(index=pd.date_range('2020-01-01', '2020-01-31'),
columns=['OpexFriday'])
isFriday = dow.index.dayofweek == 5
thirdWeek = dow.index.day.to_series().between(15,21)
# third Friday
dow['OpexFriday'] = (isFriday & thirdWeek).values
# third work week
dow['OpexWeek'] = dow['OpexFriday'].where(dow['OpexFriday']).bfill(limit=4).fillna(0)
# extract the third week:
dow[dow['OpexWeek']==1]
Output:
OpexFriday OpexWeek
2020-01-14 False 1.0
2020-01-15 False 1.0
2020-01-16 False 1.0
2020-01-17 False 1.0
2020-01-18 True 1.0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With