Skip to content
Advertisement

Checking overlaps between two columns of datetime type in Pandas DataFrame

I have a dataframe with two columns that are datetime objects (time_a and time_b). I need to check on a row-by-row basis if the elements of time_a or time_b for such row, are contained within any of the other intervals defined by the other time_a and time_b rows. That’s what I defined as ‘overlap‘, if any period of work between time_a or time_b clashes partially with other intervals regardless of the room.

The way I managed to approach this initially was to create tuples with the data of time_a and time_b, and then checking on a row-by-row basis if time_a or time_b fell within any the range of any of these tuples.

That approach seemed convoluted, so I wanted to explore the power of Pandas for such purpose. Using this great question as example, I tried adapting it to my problem, using a dataframe named test_2 (columns are date, room, time_a, time_b, personnel_number) whilst test_3 only has time_a, time_b columns. I wrote my partial solution like this:

any_in_range = lambda row, iterable: any(
    [(x > row[2]) & (x < row[3]) for x in iterable])
test_2['label_1'] = test_2.apply(any_in_range, iterable=test_3['time_case_finished'], axis=1)
test_2['label_2'] = test_2.apply(any_in_range, iterable=test_3['time_finished_cleaning'], axis=1)
test_2['isOverlap'] = np.where((test_2['label_1'] == True) | (test_2['label_2'] == True), 1, 0)
final_overlap = test_2[test_2['isOverlap'] == 1]

And a sample of the outcome, is described below:

    date    room    time_a  time_b  personnel_number    label_1 label_2 isOverlap
77  2021-09-14  3   2021-09-14 12:01:42-07:00   2021-09-14 12:12:20-07:00   1   False   False   0
80  2021-09-14  1   2021-09-14 13:15:36-07:00   2021-09-14 13:24:50-07:00   1   False   False   0
83  2021-09-14  1   2021-09-14 14:21:52-07:00   2021-09-14 14:39:37-07:00   1   True    False   1
84  2021-09-14  3   2021-09-14 14:38:58-07:00   2021-09-14 14:52:24-07:00   1   True    True    1
90  2021-09-15  4   2021-09-15 09:25:11-07:00   2021-09-15 09:53:33-07:00   1   True    True    1
91  2021-09-15  5   2021-09-15 09:28:30-07:00   2021-09-15 09:42:25-07:00   1   False   False   0
92  2021-09-15  1   2021-09-15 09:52:18-07:00   2021-09-15 10:07:25-07:00   1   True    True    1
93  2021-09-15  3   2021-09-15 10:02:05-07:00   2021-09-15 10:20:13-07:00   1   False   True    1

Now, notice how row 90 is marked as 1, but my code fails to find the other row in which it is supposed to be overlapping (which should be row 91, marking a 0). The overlap is not total, even if just a minute, I still want to count it in as overlap, but my code is not fulfilling the purpose for every case in my dataset.

Any help or advice is dearly appreciated.

Advertisement

Answer

The problem seems to boil down to finding overlapping intervals, where the intervals are defined by time_a and time_b

This can be efficiently solved with the piso (pandas interval set operations) package, in particular the adjacency_matrix method

import pandas as pd
import piso

ii = pd.IntervalIndex.from_arrays(df["time_a"], df["time_b"])
df["isOverlap"] = piso.adjacency_matrix(ii).any(axis=1).astype(int).values

note: I am the creator of piso. Please feel free to reach out with feedback or questions if you have any.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement