Multiple answers exist on how to extract data between two dates, but how can rows be selected if they fall within at least one of multiple start and end dates?
For the below data I would like to get all entries which are within x days of an event. For the below code lets assume x = 1
df = pd.DataFrame({"event": [True, False, False, False, True, False, False, False, False, False, True, True, False, False]},
index=np.arange(np.datetime64('2021-01-01'),
np.datetime64('2021-01-15'))
)
# DF
# event
# 2021-01-01 True
# 2021-01-02 False
# 2021-01-03 False
# 2021-01-04 False
# 2021-01-05 True
# 2021-01-06 False
# 2021-01-07 False
# 2021-01-08 False
# 2021-01-09 False
# 2021-01-10 False
# 2021-01-11 True
# 2021-01-12 True
# 2021-01-13 False
# 2021-01-14 False
# Desired:
# event
# 2021-01-01 True
# 2021-01-02 False
# 2021-01-04 False
# 2021-01-05 True
# 2021-01-06 False
# 2021-01-10 False
# 2021-01-11 True
# 2021-01-12 True
# 2021-01-13 False
My attemps
I assumed that intervals could be created the following way, but start and end days are identical.
intervals = [pd.Interval((x - pd.Timedelta(1, unit="days")), (x + - pd.Timedelta(1, unit="days"))) for x in df.query("event").index]
In a longer approach I used a loop to create the date ranges:
events = df.query("event").index
min_intervals = events - pd.Timedelta(1, unit="days")
max_intervals = events + pd.Timedelta(1, unit="days")
intervals = []
for i in range(len(max_intervals)):
##I could collect al entries here and merge again.
intervals = pd.Interval(min_intervals[i]:max_intervals[i])
# [Interval('2020-12-31', '2021-01-02', closed='right'),
# Interval('2021-01-04', '2021-01-06', closed='right'),
# Interval('2021-01-10', '2021-01-12', closed='right'),
# Interval('2021-01-11', '2021-01-13', closed='right')]
A single datetime can be compared against an interval:
df.index[0] in intervals[0] # == True
#So we should be able to create a mask right?
df.index in intervals[0]
# ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Anything attempted with between, isin, query failed for me.
# With the following I could create the rows for each time range. But do I really have to loop
# over each interval and afterward merge the data back together and take care of duplicates?
df = df.loc[min_intervals[i]:max_intervals[i]]
Edit: The above mentioned data is just an example to keep the explanation easy. My real dataset actually contains multiple entries per day, may have gaps and the time windows +-1 day might change.
The question might not have been worded properly and the example chosen is to simplistic. You might also be interested in the following question for a more general approach: Fitler dataframe by multiple date ranges
